模板设计模式的分析和例子
先抛出两个问题:
- 模板设计模式是什么样的?
- 我们应该怎么去用模板设计模式?
为了帮助理解,举一个生活中例子来说明:
张三和李四是好朋友,周末相约各自带着家人动物园一日游。
周末,张三李四各自买票取票。张三买了普通票需要排队,李四由于常来办了VIP会员,直接走了快速通道。都进入动物园后,张三的孩子想去看大熊猫,而李四的孩子想去看大老虎,于是分开逛。最后一起离开动物园
分析下这个例子的人物的行为,可以将逛这个动物园的流程总结抽象如下:
- 买票取票
- 排队检票进入(VIP不需要排队)
- 看不同的动物(因人而异)
- 离开动物园
可以看出1、4是固定的流程,2是有触发条件的,3是个性化的。
如果以代码形式单独表现张三、李四的行为,按照以上的1、4的流程是必定会有重复代码出现。现在还只有张三、李四,如果后面还继续出现王五、牛大,那这个重复代码的体量将会变的很可观,我们怎么去解决这个问题呢?
我们可以利用Java的一个特性:继承,将通用的行为抽象到父类中,由父类决定流程的顺序,子类只关注自己的个性化内容。模板设计模式也是利用了这个特性。
模板设计模式的思想就是利用了Java的继承特性,将子类中通用的算法抽象到父类,关键的个性化逻辑交由子类完成,整个算法的执行顺序流程由父类控制
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行
在模板模式中,有几个成员需要了解
- 模板方法:通常是一个由 final 修饰的方法,其中的内容是抽象的算法,它做为一个骨架,决定了动作的顺序
- 具体方法:通常用来定义默认执行的方法,比如上述流程中的买票、离开动物园
- 抽象方法:每个子类都必须要实现的方法,一般用来给子类实现个性化的逻辑,比如上述流程中看不同的动物
- 钩子方法:通常是一个空方法,由子类决定扩展与否,影响流程的走向
上面说了很多理论理解,下面上代码~
- 首先将父类实现出来,抽象父类中模板方法 playZoo() 方法,定义了整个算法执行的流程;buyTickets() 、 play() 、commonOrVip() 是三个具体方法,由父类直接调用,子类不关注实现;commonOrVip() 具体方法比较特殊,它是由钩子方法 isVip() 确定执行流程的,而钩子方法的具体返回可以由子类选择是否控制,也就是说,子类可以通过钩子方法影响整体的执行流程的
public abstract class AbstractGoZoo {
/**
* 定义算法的骨架
* 模板方法
* 为了防止恶意操作,加上final方法
*/
public final void playZoo() {
buyTickets();
commonOrVip();
play();
leaveZoo();
}
/**
* 具体方法
*/
private void leaveZoo() {
System.out.println("离开动物园!");
}
/**
* 抽象方法
*/
protected abstract void play();
/**
* 具体方法
*/
private void commonOrVip() {
if (isVip()) {
System.out.println("绿色通道!");
} else {
System.out.println("排队检票!");
}
}
/**
* 钩子方法
*/
public boolean isVip() {
return false;
}
/**
* 具体方法
*/
private void buyTickets() {
System.out.println("买票!");
}
}
- 上张三的代码,该段代码只实现了 play() 抽象方法
public class ZhangSan extends AbstractGoZoo {
@Override
protected void play() {
System.out.println("我们去看大熊猫!");
}
}
- 上李四的代码 ,该段代码实现了 play() 抽象方法,重写了钩子方法 isVip(),将会影响执行流程
public class Lisi extends AbstractGoZoo {
@Override
protected void play() {
System.out.println("我们去看大老虎!");
}
@Override
public boolean isVip() {
return true;
}
}
- 看看执行结果
从上面的代码和结果看,张三除了个性化看的动作外,对流程没有改变。李四不仅个性化了自己看的动作,还改变了检票的流程执行。
总结
- 当有一类行为都有共通的逻辑时,我们可以使用模板设计模式,封装不变部分,扩展可变部分。行为方式由父类控制,子类控制具体实现
- 优点:提取公共代码,便于维护;缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
- 注意事项:模板方法,一般都使用final修饰,防止恶意重写模板方法
模板模式总体来说是对行为抽象和控制,所以属于设计模式中的行为型
写完,收工~