Template Method模式
在父类中定义处理流程的框架,在子类中实现具体的模式就是Template Method
模式。
在Template Method模式中,处理的流程被定义在父类中,而具体的处理则交个子类。
实现
AbstractDisplay.java
public abstract class AbstractDisplay {
public abstract void open();
public abstract void print();
public abstract void close();
// 注意这里使用了final 通常不希望模板方法被重写
public final void display() {
open();
for (int i = 0; i < 5; i++) {
print();
}
close();
}
}
CharDisplay.java
public class CharDisplay extends AbstractDisplay {
private char ch;
public CharDisplay(char ch) {
this.ch = ch;
}
public void open() {
System.out.print("<<");
}
public void print() {
System.out.print(ch);
}
public void close() {
System.out.println(">>");
}
}
StringDisplay.java
public class StringDisplay extends AbstractDisplay {
private String string;
private int width;
public StringDisplay(String string) {
this.string = string;
this.width = string.getBytes().length;
}
public void open() {
printLine();
}
public void print() {
System.out.println("|" + string + "|");
}
public void close() {
printLine();
}
private void printLine() {
System.out.print("+");
for (int i = 0; i < width; i++) {
System.out.print("-");
}
System.out.println("+");
}
}
登场角色
AbstractClass(抽象类):实现模板方法,并且负责声明在模板方法中所使用到的抽象方法。
ConcreteClass(具体类):负责具体实现AbstractClass角色中所定义的抽象方法。
站在子类的角度
- 在子类中可以使用父类中定义的方法
- 可以通过在子类中增加方法以实现新的功能
- 在子类中重写父类的方法可以改变程序的行为
站在父类的角度
- 期待子类去实现抽象方法
- 要求子类去实现抽象方法
子类具有实现在父类中所声明的抽象方法的责任,这种责任也被称为“子类责任”(subclass responsibility)。
要点思考
在抽象类阶段确定处理的流程非常重要,父类中的模板方法中编写了算法,从而无需在每个子类中再编写算法,当在模板方法中发现bug时,只需要修改模板方法即可解决问题。
我们应当使用父类类型的变量保存子类实例,这样即使没有用instanceof
等指定子类的种类,程序也能正常工作。无论在父类类型的变量中保存哪个子类的实例,程序都可以正常工作,这种原则称为里氏替换原则(Liskov Substitution principle, LSP)。当然,LSP并未局限于Template Method模式,它是通用的继承原则。
更多的将方法的实现放在父类中会让子类变得更加轻松,但是降低了子类的灵活性;如果父类中实现的方法过少,子类就会变得臃肿不堪。这些都需要负责程序设计的开发人员来决定。
示例代码出自《图解设计模式》 结城浩