【问题标题】:Template method and inheritance or composition模板方法和继承或组合
【发布时间】:2019-02-22 09:42:33
【问题描述】:

我有这些课程:

@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. 我是否正确理解使用模板方法时,我附加到继承?

模板方法是避免重复的好方法。但是如果它将我绑定到继承,还有什么其他方法可以避免代码重复?在我的示例中,如何使用组合? (把模板方法换成别的?)

【问题讨论】:

    标签: java inheritance design-patterns composition template-method-pattern


    【解决方案1】:

    1) 如何重写此代码以使用组合?

    Strategy Pattern 是一种方式。本质上,您将通过将操作传递到数据中而不是将数据传递到操作中来反转数据和操作之间的关系。这是一个根本性的变化,因为使用“真实”对象(具有状态和行为)而不是数据类。

    2) 我是否正确理解使用模板方法时,我附加到继承?

    是的,模板方法模式基本上是基于继承的。

    【讨论】:

      【解决方案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);
      

      【讨论】:

      • 感谢您的示例!但这里的重复问题并没有解决。因为在updateName 之前和之后System.out.println(t); 我有很多代码行,并且在每个代理类中,此代码都会重复。我需要所有类都使用相同的算法。并且只改变这个算法的一小部分
      • @ip696 您不必细化代理类。您可以将小部分的操作实现为委托,并用它创建一个代理对象。
      • 全错了。我有一个算法。执行此算法时,会调用不同的方法。带有不同的签名。他们被实现为继承人。具有相同接口的类数组有什么用?很可能没有替代模板方法中的逻辑实现
      • 当我有相同的代码时,代理运行良好,但我需要在它之前或之后运行另一个代码。而且我需要保留外部代码(我的算法),并且只有部分代码内部发生变化
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-05
      • 2013-06-02
      • 2012-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-07
      相关资源
      最近更新 更多