Шаблонный метод и наследование или композиция
У меня есть следующие занятия:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Admin {
private String name;
private int age;
}
И у меня есть некоторые операции с реализацией шаблона метода шаблона. Базовый класс с алгоритмом:
public abstract class Operation<T> {
public void process(T t){
System.out.println(t);
updateName(t);
System.out.println(t);
}
protected abstract void updateName(T t);
}
два ребенка с методом реализации шаблона:
@Component
public class UserOperation extends Operation<User> {
@Override
protected void updateName(User user) {
String newName = user.getName().toUpperCase();
user.setName(newName);
}
}
@Component
public class AdminOperation extends Operation<Admin> {
@Override
protected void updateName(Admin admin) {
String name = admin.getName();
StringBuilder builder = new StringBuilder();
builder.append(name);
StringBuilder reverse = builder.reverse();
admin.setName(reverse.toString());
}
}
Мои вопросы:
1) Как мне переписать этот код для использования композиции?
2) Правильно ли я понимаю, что при использовании метода шаблона я присоединяюсь к наследованию?
Шаблонный метод - отличный способ избежать дублирования. Но если это связывает меня с наследованием, каковы другие способы избежать дублирования кода? в моем примере, как я могу использовать композицию? (заменить метод шаблона чем-то другим?)
2 ответа
1) Как мне переписать этот код для использования композиции?
Шаблон стратегии - это один из способов. По сути, вы бы изменили связь между данными и операциями, передавая операции в данные, а не передавая данные в операции. Это фундаментальное изменение, поскольку вместо классов данных используются "реальные" объекты (с состоянием и поведением).
2) Правильно ли я понимаю, что при использовании метода шаблона я присоединяюсь к наследованию?
Да, шаблонный шаблонный метод основан на наследовании.
Вместо шаблона вы можете использовать прокси:
public abstract class Operation<T> {
public abstract void updateName(T t);
}
public class OperationProxy<T> extends Operation<T> {
private final Operation<T> delegate;
public OperationProxy(Operation<T> delegate) {
this.delegate = delegate;
}
@Override
public void updateName(T t){
System.out.println(t);
delegate.updateName(t);
System.out.println(t);
}
}
Обратите внимание, что это позволит вам сделать класс Operation
и интерфейс.
ОБНОВИТЬ
Другая возможность - определение последовательности операций и операции печати (даже больше кода):
public interface Operation<T> {
void updateName(T t);
}
public class OperationSequence<T> implements Operation<T> {
private final Operation<T>[] steps;
public OperationSequence(Operation<T>... steps) {
this.steps = steps;
}
@Override
public void updateName(T t){
for (Operation<T> step: steps) {
step.updateName(t);
}
}
}
public class PrintOperation<T> implements Operation<T> {
@Override
public void updateName(T t){
System.out.println(t);
}
}
Теперь вы можете использовать следующий код:
Operation<MyClass> print = new PrintOperation<>();
Operation<MyClass> seq = new OperationSequence<>(
print, (t) -> {doSomethingWith(t);}, print);