Template Method(模板方法):在你想要灵活更改原始选项时如何使用它?

huangapple go评论80阅读模式
英文:

Template Method: How to use it when you want to be able to flexibly change primitive options?

问题

The problem is best explained with the following code:

公开类 TemplateClass {
公开 void templateOne() {
检查条件A();
原始操作1();
检查条件B();
}

公开 void templateTwo() {
    检查条件A();
    原始操作2();
    检查条件B();
}

受保护的抽象 void 原始操作1();
受保护的抽象 void 原始操作2();
// 其余方法

}

现在我在 templateOne() 和 templateTwo() 中有代码重复,但我希望只有一个模板方法,但原始操作可以互换。

英文:

The problem is best explained with the following code:

public class TemplateClass {
    public void templateOne() {
        checkConditionA();
        primitiveOp1();
        checkConditionB();
    }

    public void templateTwo() {
        checkConditionA();
        primitiveOp2();
        checkConditionB();
    }

    protected abstract void primitiveOp1();
    protected abstract void primitiveOp2();
    // rest of the methods
}

Now I have code duplication with templateOne() and templateTwo(), but I would like to have just one template method but with interchangeable primitive operations.

答案1

得分: 2

你想要的实质上是在方法调用周围添加一个保护块。DRY编程是一个好的实践,但要注意不要将不应该耦合在一起的东西耦合在一起。只有在可以保证它们必须始终由相同的前置条件和后置条件保护时,我才会将这两个方法耦合在一起。

如果是这种情况,我建议实现一个方法 private void callWithChecks(Runnable primitiveOperation),然后将相应的原始操作作为参数传递给这个方法:

public abstract class TemplateClass {
    public void templateOne() {
        callWithChecks(this::primitiveOp1);
    }

    public void templateTwo() {
        callWithChecks(this::primitiveOp2);
    }

    private void callWithCkecks(Runnable primitiveOperation) {
        checkConditionA();
        primitiveOperation.run();
        checkConditionB();
    }

    protected abstract void primitiveOp1();
    protected abstract void primitiveOp2();
    // 其他方法
}

如果你不想使用函数接口 Runnable,当然可以定义自己的接口。我选择它,因为它是一个Java基类。


关于你的代码有两点备注:

  • TempalteClass 必须声明为 abstract,否则代码将无法编译。
  • 如果你打算在 TemplateClass 中实现方法 checkConditionA()checkConditionB(),我建议将它们定义为 privatefinal,以防止它们被覆盖。
英文:

What you want is, in essence, a guard block around a method call. DRY programming is good practice, but be advice that you do not wawnt to couple what should not be coupled. I would only couple those two methods if it is guaranteed that they must always be guarded by the same pre- and postcondition(s).

If this is the case, I would recommend to implement a method private void callWithChecks(Runnable primitiveOperation) and then pass the respective primitive operation as parameter to this method:

public abstract class TemplateClass {
    public void templateOne() {
        callWithChecks(this::primitiveOp1);
    }

    public void templateTwo() {
        callWithChecks(this::primitiveOp2);
    }

    private void callWithCkecks(Runnable primitiveOperation) {
        checkConditionA();
        primitiveOperation.run();
        checkConditionB();
    }

    protected abstract void primitiveOp1();
    protected abstract void primitiveOp2();
    // rest of the methods
}

If you do not want to use the function interface Runnable, you can of course define your own interface. I went with it, since it is a Java base class.


Two remarks on your code:

  • TempalteClass must be declared abstract, otherwise the code will not compile
  • If you intend to implement methods checkConditionA() and checkConditionB() within TemplateClass, I would recommend defining them as private or final such that they cannot be overridden.

huangapple
  • 本文由 发表于 2020年8月13日 01:35:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/63381931.html
  • code-duplication
  • design-patterns
  • java
  • strategy-pattern
  • template-method-pattern
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定