一、概述
模版方法模式的官方定义:
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中去实现。
模版方法模式可以在不改变一个算法的结构的前提下重新定义该算法的某些特定步骤
通俗的理解:
模版方法模式其实就是首先创造一个模版或者说规则,比如我定好步骤1、2、3、4、5,父类会维护这个12345步骤的顺序,但是不会把这些步骤全部全部实现,假设1、2、3、5是固定不变的,4父类不去实现,而是交给子类来进行实现,只要是符合规矩的操作,你都可以写在4中,到最后将子类对象通过多态(动态绑定)来绑定给一个父类的对象,父类直接调用模版方法来进行操作。
模版方法:就是在父类中规定好的步骤的执行顺序的方法,他只会关心步骤的顺序性而不会去管抽象的扩展方法是否被实现(实现是由子类完成的)
模版方法的使用场景:
- 一次性实现一个算法的不变部分,并且把可变的部分留给子类来实现
- 提取各个子类的共同部分到父类中,避免代码的冗余和重复
- 控制子类的拓展性,使得子类只可以在特定的部分进行拓展
二、角色职责与UML
2.1 角色与职责
AbstractClass(抽象类)
- 定义类的抽象方法,具体的实现由子类来完成
- 实现一个模版方法来作为算法的骨架。该方法不仅调用抽象方法,也会去调用其他已实现的方法
ConcreteClass(具体实现类)
- 实现父类中的抽象方法来完成算法骨架中抽象出的步骤
2.2 UML类图
三、示例
嗯……作为一个Java程序猿,相信大家都会听过一个梗,就是“把大象放入冰箱有几步”,我也相信大家的回答一定是三步,打开冰箱、把大象放进去、关上冰箱。
那我们这次就拿这个梗来举例吧,假设我们有一个冰箱的类,他提供了打开门、放入东西、关上门三个操作,但是我们不确定每次放入冰箱的东西是什么,所以我们使用模版方法来将操作冰箱的步骤固定,然后将放入东西的方法抽象,由子类来完成放入冰箱的方法,不论是放什么东西、怎么放,切片也好切丝也罢,反正这不是我父类需要考虑的事情了,我父类作为一个冰箱我只需要告诉你打开门才可以放东西,放完东西需要关门,仅此而已。
首先创建我们的冰箱类,在其中定义开关门的方法和放东西的抽象方法以及提供一个维持算法骨架步骤的模版方法
/**
* @author ZhongJing </p>
* @Description 冰箱:拥有开门、关门、放东西三个方法 </p>
*/
public abstract class RefrigeratorTemplate {
/**
* 打开冰箱门
*/
public void open() {
System.out.println("打开冰箱门");
}
/**
* 关闭冰箱门
*/
public void close() {
System.out.println("关闭冰箱门");
}
/**
* 把东西放到冰箱
*/
public abstract void putIn();
/**
* 模版方法:规定使用冰箱的步骤
*/
public void template() {
open();
putIn();
close();
}
}
然后我们写一个类来实现大象放入冰箱的具体步骤
/**
* @author ZhongJing </p>
* @Description 具体实现类:实现把大象放入冰箱的操作 </p>
*/
public class ElephantInRefrigerator extends RefrigeratorTemplate{
@Override
public void putIn() {
System.out.println("把大象切块,放入冰箱");
}
}
测试类:
/**
* @author ZhongJing </p>
* @Description 模版方法模式测试类 </p>
*/
public class MainTest {
public static void main(String[] args) {
RefrigeratorTemplate refrigeratorTemplate = new ElephantInRefrigerator();
refrigeratorTemplate.template();
}
}
运行结果:
打开冰箱门
把大象切块,放入冰箱
关闭冰箱门
四、总结
大概总结一下吧,大象装进冰箱的例子经过测试结果也已经贴出来了,现在我们来谈谈为什么。
首先呼应概述中解释的概念,这样做的好处,首先冰箱一定是会拥有开关门的功能的,我们将这些方法提取成了公共方法放在了父类中,那么我们如果以后再来一些比如把野猪放进冰箱、把奶牛放进冰箱这些操作的时候我们也不需要再在其中写开关门这些基础操作了,并且将放入冰箱的操作抽象出来的好处也体现了出来,不管你想放什么,我不管你,但是总的来说就是开门、放东西和关门,怎么放都随你,你想咋放咋放,我只需要维护我的逻辑顺序。
模版方法模式还是比较简单的,就是面向对象知识的简单运用,但是非常实用,我们熟悉的Spring框架中也大量的使用的模版方法模式,比如说常见的BeanFactory就是一个模版、还有JdbcTemplate、RedisTemplate、RabbitTemplate等等,这些都允许我们再次对其进行扩展和自定义