看源码时不难发现,一般的套路是:
1、顶级一个接口,如Display,内部可能会定义几个抽象方法;
2、接下来是一个抽象类AbstractDisplay来实现接口Display,然后再去扩展几个自己的方法;
3、然后是具体的类,XXXDisplay继承自AbstractDisplay,并去重写父类方法等
通常在第2步时发现,虽然当前类为一个抽象类,但是里面却有部分的有方法体的方法(可能被final修时,也可能没有被final修时),并且这些方法体内部调用了抽象方法。具有这种特征的模式即为模板方法。
显而易见,抽象类中定义了模板方法,但又需要子类自己的逻辑去配合父类的模板方法才能完成最终的方法调用。下面搞个例子来说明一下:
//定义一个抽象类
public abstract class AbstractDisplay {
/**
* 定义抽象方法 open
*/
public abstract void open();
/**
* 定义抽象方法 print
*/
public abstract void print();
/**
* 定义抽象方法close()
*/
public abstract void close();
public final void display(){
open();
for (int i = 0; i < 5; i++) {
print();
}
close();
}
}
//定义一个具体类的子类
public class CharDisplay extends AbstractDisplay{
private String msg;
public CharDisplay(String msg) {
this.msg = msg;
}
@Override
public void open() {
System.out.println(">>>>>>>>");
}
@Override
public void print() {
System.out.println(msg);
}
@Override
public void close() {
System.out.println("<<<<<<<<");
}
}
//定义一个具体的子类
public class StringDisplay extends AbstractDisplay {
private String msg;
public StringDisplay(String msg) {
this.msg = msg;
}
@Override
public void open() {
System.out.println("||||||||||||");
}
@Override
public void print() {
System.out.println(msg);
}
@Override
public void close() {
System.out.println("|||||||||||||");
}
}
//main方法验证
public static void main(String[] args) {
AbstractDisplay charDisplay = new CharDisplay("HELLO WORLD!");
AbstractDisplay stringDisplay = new StringDisplay("你好,世界!");
charDisplay.display();
stringDisplay.display();
}
//console的输出结果
>>>>>>>>
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
<<<<<<<<
||||||||||||
你好,世界!
你好,世界!
你好,世界!
你好,世界!
你好,世界!
|||||||||||||
正如示例代码所示:
1、父类(抽象类)定义了抽象方法和模板方法
2、子类实现抽象方法
3、在执行父类的模板方法的时候发现,具体的逻辑会根据具体的子类型来确定。这就
实现了一个模板算法下的不同的实现内容
到此大家应该也对模板方法有了个大概的认识,下面我们来总结一下模板方法的重要特征(敲黑板):
1、关于模板方法Template Method的角色划分:抽象类和具象子类
2、父类和子类共同参与,团结协作。
3、父类和子类的一致性,使用父类型来保存子类实例,这样的好处在于即使没有instanceof来指定子类
类型,程序也能跑,这属于典型的LSP(里氏代换)