目录
一、定义
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
二、UML图
模板方法模式涉及到的角色:
抽象模板角色:定义一组基本方法供子类实现,定义并实现组合了基本方法的模板方法。
具体模板角色:实现抽象模板角色定义的基本方法。
模板方法模式涉及到的方法的概念:
基本方法
抽象方法:由抽象模板角色声明,abstract修饰,具体模板角色实现。
钩子方法:由抽象模板角色声明并实现,具体模板角色也可实现加以扩展。
具体方法:由抽象模板角色声明并实现,而子类并不需要实现。
模板方法
抽象模板角色声明并实现,负责对基本方法的调度,一般以final修饰,不允许具体模板角色重写。模板方法一般也是一个具体的方法。
三、Demo演示
这里我们以生活中骑共享单车的例子来进行讲解说明。
1.我们先定义一个抽象的模板类:
public abstract class Bicycle {
/**
* 默认需要开锁
*/
protected boolean isNeedUnlock = true;
/**
* 抽象方法,子类需要实现
*/
protected abstract void unlock();
/**
* 抽象方法,子类需要实现
*/
protected abstract void ride();
/**
* 钩子方法,子类需要时可实现
*
* @param isNeedUnlock
*/
protected void isNeedUnlock(boolean isNeedUnlock) {
this.isNeedUnlock = isNeedUnlock;
}
/**
* 模板方法,负责调度基本方法,子类不可实现
*/
public final void use() {
if (isNeedUnlock) {
unlock();
}
ride();
}
}
2.然后定义一个扫码开锁的单车类:
public class ScanBicycle extends Bicycle {
@Override
protected void unlock() {
System.out.println("========" + "扫码开锁" + "========");
}
@Override
protected void ride() {
System.out.println(getClass().getSimpleName() + "骑起来很拉风"); }
}
3.再定义一个密码开锁的单车类:
public class CodeBicycle extends Bicycle {
@Override
protected void isNeedUnlock(boolean isNeedUnlock) {
super.isNeedUnlock(isNeedUnlock);
}
@Override
protected void unlock() {
System.out.println("========" + "密码开锁" + "========");
}
@Override
protected void ride() {
System.out.println(getClass().getSimpleName() + "骑起来很拉风");
}
}
4.测试类:
public class Client {
public static void main(String[] args) {
ScanBicycle scanBicycle = new ScanBicycle();
scanBicycle.use();
CodeBicycle codeBicycle = new CodeBicycle();
codeBicycle.use();
}
}
5.输出结果:
========扫码开锁========
ScanBicycle骑起来很拉风
========密码开锁========
CodeBicycle骑起来很拉风
四、总结
优点:
(1)良好的封装性:把公有的不变的方法封装在父类,而子类负责实现具体逻辑。
(2)良好的扩展性:增加功能由子类实现基本方法扩展,符合单一职责原则和开闭原则。
(3)代码复用性较好。
缺点:
(1)由于是通过继承来实现代码复用,继而来改变算法,灵活度会降低。
(2)子类的执行影响父类的结果,增加来代码阅读的难度。
另外,模版方法模式在一些开源框架里面也有很好的体现,比如Tomcat源码里,在各个组件初始化(init)、启动(start)和停止(stop)的方法上,就使用的是模版方法模式。大家有兴趣的可以自己去看一看,这里我们就不详细展开了。
参考资料:
《大话设计模式》、《Head First》