模板方法模式是什么?
我的理解是:在抽象父类中定义好一套“处理通用业务流程的顺序”,但是其中”具体的处理细节“交给子类实现,这样我们只需要调用父类这个方法去处理业务即可。
像这样在父类中定义处理流程的框架,在子类中实现具体处理的模式就成为TemplateMethod模式。
为什么要用这种模式?
- 可以使逻辑处理通用化。在父类的模板方法中编写了算法,因此无需在每个子类中再编写算法,出现bug时也只需改动父类一个地方即可。
- 使用父类类型的变量保存子类实例,优点是即使没有用instanceof等指定子类的种类,程序也能正常工作。
里氏替换原则
这里涉及到一个重要原则:无论在父类类型的变量中保存哪个子类的实例,程序都可以正常工作,这种原则称为”里氏替换原则(LSP)”。
代码
比如这样一个需求,用户A需要输出一个字符,但是输出字符前后要用 “《” “》” 括起来;用户B需要输出一个字符串,但是输出前后也要将字符串“包”起来。
此时就可以将这个”包“起来的动作抽象成一套通用的"处理业务流程的框架“,而具体实现(输出字符还是字符串)就交给子类。
public abstract class AbstractDisplay {
public final void display() {
open();
for (int i=0; i<5; i++) {
print();
}
close();
}
public abstract void open();
public abstract void print();
public abstract void close();
}
子类1:
public class CharDisplay extends AbstractDisplay {
private char c;
public CharDisplay(char c) {
this.c = c;
}
@Override
public void open() {
System.out.print("<<");
}
@Override
public void print() {
System.out.print(c);
}
@Override
public void close() {
System.out.println(">>");
}
}
子类2:
public class StringDisplay extends AbstractDisplay {
private String str;
private int width;
public StringDisplay(String str) {
this.str = str;
this.width = str.getBytes().length;
}
@Override
public void open() {
printLine();
}
@Override
public void print() {
System.out.println("|" + str + "|");
}
@Override
public void close() {
printLine();
}
private void printLine() {
System.out.print("|");
for (int i = 0; i < width; i++) {
System.out.print("-");
}
System.out.println("|");
}
}
测试:
public class Test {
public static void main(String[] args) {
AbstractDisplay display = userA();
display.display();
display = userB();
display.display();
}
public static AbstractDisplay userA() {
return new CharDisplay('a');
}
public static AbstractDisplay userB() {
return new StringDisplay("hello world");
}
}
可以看到我们只需要用父类引用去接用户传过来的子类,然后调用display()这个通用的”处理业务流程的逻辑“就行了,至于具体要怎么输出,那就看子类是怎么实现的。
甚至还可以将父类的模板方法(display)定义为final。推荐模板方法无法被重写