模板模式(Template Pattern)又被称作模板方法模式(Template Method Pattern),它是一种简单的、常见的且应用非常广泛的模式。
英文定义如下:
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.
意思是:定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
简单来说,就是为子类设计一个模板,以便在子类中可以复用这些方法。
模板模式包含如下角色:
角色之间的 UML 关系图如下:
/**
* 抽象模板
*/
abstract class AbstractTemplate {
// 模板方法
public void templateMethod() {
//(所有)基本方法
abstractMethod();
hookMethod();
concreteMethod();
}
// 抽象方法,必须有子类实现
protected abstract void abstractMethod();
// 钩子方法,子类可以选择重写或不重写
protected void hookMethod() {
}
// 具体方法,子类不可修改
private final void concreteMethod() {
System.out.println("抽象类中的具体方法");
}
}
/**
* 具体模板 A 类
*/
class ConcreteTemplateA extends AbstractTemplate {
@Override
protected void abstractMethod() {
System.out.println("A 子类中重写的抽象方法");
}
}
/**
* 具体模板 B 类
*/
class ConcreteTemplateB extends AbstractTemplate {
@Override
protected void abstractMethod() {
System.out.println("B 子类中重写的抽象方法");
}
}
public class Client {
public static void main(String[] args) {
AbstractTemplate tp = new ConcreteTemplateA();
// 调用子类 A 的模板方法
tp.templateMethod();
tp = new ConcreteTemplateB();
// 调用子类 B 的模板方法
tp.templateMethod();
}
}
程序执行结果如下:
A 子类中重写的抽象方法 抽象类中的具体方法 B 子类中重写的抽象方法 抽象类中的具体方法
从以上代码可以看出,在模板模式中,方法分为两类:模版方法和基本方法,而基本方法又分为:抽象方法,具体方法,钩子方法。
小贴士:一个模板方法是定义在抽象类中的,把基本操作方法组合在一起形成一个总算法或一个总行为的方法。 一个抽象类可以有任意多个模板方法,而不限于一个,每一个模板方法都可以调用任意多个具体方法。
模板模式的优点:
模板模式的缺点:
模板模式的典型应用场景如下:
以生活中上班的过程为例,我们上班的通常流程是:起床洗漱 -> 通勤(开车、坐公交、打车) -> 到达公司。从以上步骤可以看出,只有通勤部分是不一样的,其他都一样,因为开车可能会被限号,就只能打车或坐公交去公司了,下面我们用代码(模板模式)来实现一下。
/**
* 上班抽象(模板)类
*/
abstract class AbstractWork {
// 模板方法
public void gotoWork() {
getup();
commute();
arrive();
}
// 起床洗漱
public void getup() {
System.out.println("1.起床洗漱");
}
// 通勤
abstract void commute();
// 到达公司
public void arrive() {
System.out.println("3.到达公司");
}
}
/**
* 开车上班
*/
class DriveToWork extends AbstractWork {
@Override
void commute() {
System.out.println("2.开车去公司");
}
}
/**
* 坐公交上班
*/
class BusToWork extends AbstractWork {
@Override
void commute() {
System.out.println("2.坐公交去公司");
}
}
public class Client {
public static void main(String[] args) {
AbstractWork work = new DriveToWork();
// 开车上班
work.gotoWork();
work = new BusToWork();
// 坐公交上班
work.gotoWork();
}
}
程序执行结果如下:
1. 起床洗漱 2. 开车去公司 3. 到达公司 1. 起床洗漱 2. 坐公交去公司 3. 到达公司
模板模式的精髓是复用抽象类中的公共方法,重写抽象类中的基础(抽象)方法,选择性使用抽象类中的钩子(hook Method)方法。使用模板模式的关键是:子类可以置换掉父类的可变部分,但是子类却不可以改变模板方法所代表的顶级逻辑。