模板方法模式是比较简单的模式,在框架中用处也很多,这里介绍下基本实现,和几个理解上的关键点。
1、定义和类图
定义一个抽象类,将部分逻辑使用具体方法或构造方法在抽象类中实现,另一部分逻辑,在抽象类中定义成抽象方法,强迫子类是实现。这样,不同的子类对于抽象方法的实现逻辑就可以不一样。这就是模板方法模式的意义。类图如下:
从类图中可以看到,抽象类中有一个模板方法template Method,一个抽象方法abstract Method,一个钩子方法hook Method,还有一个具体方法concrete Method. 一般模板方法只有一个,作为主逻辑,调用其他方法,其他类型可以有多个。子类中,实现了abstract Method 和 hook Method.
关键点:
- 模板方法中定义了主流程的逻辑,调用abstract Method,hook Method 和 concrete Method,从而完成整个逻辑
- 模板方法中最重要的一点,就是客户端代码中,调用的是子类对象的模板方法,比如上面类图中的concreteTemplate.templateMethod()。因为子类是继承了抽象类的,所以抽象类里的方法,子类自然可以使用。但是抽象类里的抽象方法和hook方法并没有实现,所以真正调用的还是子类自己的抽象方法和hook方法。这是一个反向控制的结构,是父类调用子类的方法,而不是常见的子类调用父类,这个是模板方法的典型应用
- 抽象方法在子类中实现,重要的是参与,实现这一个环节,使主流程可以跑通。策略模式使用接口而不是抽象类实现,虽然类图有点相似,本质与模板方法完全不同
- hook Method,其实是可有可无的。在框架中,也不一定叫这个名字,比如servlet里面的doGet(), doPost() 之类,都是这种。这么用的主要用意,是为了让用户或者程序员自己继承框架的类,然后实现这几个钩子方法,那么在运行时,就是让框架可以调用了用户的代码。比如典型的例子,像hadoop里的Map和Reduce
- 模板方法模式,应用场景一般是,一些功能的大部分逻辑相同,但是一些具体的逻辑不一样,如果直接写在一个类里,需要不断的用if else,或者类似的方法去判断,使用模板方法模式可以避免这种情况。当具体逻辑添加或者删除的时候,只需要修改那个对应的类,更方便的扩展。
最后贴一段代码。
public abstract Class Template {
//定义一个主流程,子类一般不能去改变
protected void templateMethod() {
//调用具体方法,该类中已实现
concreteMethod();
//抽象方法
abstractMethod();
//钩子方法
hooks();
}
private void concreteMethod() {
//业务逻辑
}
protected void abstractMethod();
protected void hooks();
}
public Class ConcreteTemplate {
@Override
protected void abstractMethod() {
//业务逻辑
}
@Override
protected void hooks() {
//什么都不干
}
}
public Class Client {
public static void main(String[] args) {
Template template = new ConcreteTemplate();
template.templateMethod();
}
}