1. 什么是模板方法模式?
《Head First设计模式》书中定义:在一个方法中定义一个算法的骨架,而将一些步骤的实现延迟到子类中。模板方法模式使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
模板方法模式为我们提供了一种代码复用的重要技巧。模板方法的抽象类可以定义抽象方法、具体方法(具体方法中也可以包含钩子方法)。抽象方法由子类实现。钩子方法子类可以选择性重写覆盖。
钩子是一种被声明在抽象类中的方法,但只有空的或者是默认的实现。钩子的存在可以使子类有能力对算法的不同点进行挂钩(重写覆盖),是否挂钩,由子类自行决定。
为了防止子类改变模板方法的算法骨架,可以将模板方法声明为final。
OO设计原则-好莱坞原则:“别调用我,我会调用你”。低层组件绝对不可以直接调用高层组件。好莱坞原则将决策权放在高层模块中,以便决定如何以及何时调用低层模块。
模板方法模式的关键在于,子类可以替换父类算法可变的部分,但是不能更改父类模板方法中的顶级逻辑。
2. 角色
抽象模板类(AbstractClass):定义了一系列基本方法,这些基本方法可以是具体的,也可以是抽象的,每一个基本方法都是算法骨架中的一个步骤,子类中可以重新定义或实现这些步骤。同时,在抽象类中还提供了一个模板方法,用于定义一个算法的骨架,模板方法不仅可以调用自身的基本方法,也可以调用子类实现的基本方法或其他类的方法。
具体方法类(ConcreteClass):具体方法类需要实现抽象模板类中的抽象方法以实现模板方法中的特定步骤。也可以选择性的重写覆盖钩子方法。
图片来源于《Head First设计模式》
3. 优点
(1)提供了一种代码复用的方式,可以将可变部分抽象出来由子类实现,增加了系统灵活性。由于父类实现公共不变部分,子类提供可变的部分,因此子类可以提供不同的实现,系统增加更换子类很方便,符合开闭原则和单一职责原则。
(2)可以实现反向控制结构,子类通过覆盖父类的钩子方法可以控制父类某一特定步骤是否执行。
4. 缺点
(1)由于可变部分抽象出来,单独由子类实现,增加了类的数量,系统更加庞大。
5. 使用场景
(1)一组特定操作中存在几种可变步奏的时候,可以使用模板方法模式将可变部分抽象出来单独由子类实现。
(2)需要使用子类控制父类的反向控制结构的时候。
(3)使用Servlet时,除了要在web.xml做相应的配置外,还需继承一个叫HttpServlet的抽象类。HttpService类提供了一个service()方法,这个方法调用七个do方法中的一个或几个,例如doPost()、doGet()等,完成对客户端调用的响应。这些do方法需要由HttpServlet的具体子类提供,因此这是典型的模板方法模式。
6. 示例代码
(1)抽象模板类
/**
* 抽象父类,其中最重要的是模板方法templateMethod()
* 其中定义了算法执行步骤
*/
public abstract class AbstractTemplate {
/**
* 模板方法
*/
public final void templateMethod(){
if(hookMethod())
concreteMethod();
abstractMethod();
}
/**
* 抽象方法,由子类实现
*/
protected abstract void abstractMethod();
/**
* 钩子方法,子类可以选择性的重写覆盖
* 默认返回true
*/
protected boolean hookMethod(){
return true;
}
/**
* 具体方法
*/
protected final void concreteMethod(){
System.out.println("this is concreteMethod.");
}
}
(2)具体实现类
public class ConcreteTemplate extends AbstractTemplate {
@Override
protected void abstractMethod() {
System.out.println("this is ConcreteTemplate's abstractMethod.");
}
/**
* 重写覆盖钩子方法,控制父类不执行concreteMethod()方法
*/
@Override
protected boolean hookMethod() {
return false;
}
}
(3)测试代码
public class Client {
public static void main(String[] args) {
AbstractTemplate at=new ConcreteTemplate();
at.templateMethod();
}
}
(4)测试结果
(a)当子类ConcreteTemplate不覆盖钩子方法时:
this is concreteMethod.
this is ConcreteTemplate's abstractMethod.
(b)当子类ConcreteTemplate重写覆盖钩子方法时:
this is ConcreteTemplate's abstractMethod.
【四川乐山程序员联盟,欢迎大家加群相互交流学习5 7 1 8 1 4 7 4 3】