模板方法模式是最为简单也最常用的设计模式之一了,它主要利用了Java的多态的特性,通过把所有的不会变化的定义放到一个抽象类(模板类)里实现,会变化的方法定义成抽象方法,再使用其子类对会变化的地方进行自定义实现。
模板方法模式的定义: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. (定义一个操作中的算法的框架, 而将一些步骤延迟到子类中。 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 )
这次我们还是拿汽车厂制造白色、黑色汽车这个业务场景来举例讲解:普通实现到模板方法模式的演进
普通实现
类图:
代码:
-
定义两个颜色的汽车工厂
/** * 生产白色汽车的工厂 */ public class WhiteCarFactory { void createFrame(){ System.out.println("制造汽车框架"); } void installComponent(){ System.out.println("安装零件"); } void coloring() { System.out.println("给汽车喷上白色的车漆"); } void over(){ System.out.println("汽车制造完毕"); } void builderCar(){ // 1. 制造汽车框架 createFrame(); // 2. 安装汽车零件 installComponent(); // 3. 汽车喷漆,上色 coloring(); // 4. 汽车制造完毕 over(); } } /** * 生产黑色汽车的工厂 */ public class BlackCarFactory { void createFrame(){ System.out.println("制造汽车框架"); } void installComponent(){ System.out.println("安装零件"); } void coloring() { System.out.println("给汽车喷上黑色的车漆"); } void over(){ System.out.println("汽车制造完毕"); } void builderCar(){ // 1. 制造汽车框架 createFrame(); // 2. 安装汽车零件 installComponent(); // 3. 汽车喷漆,上色 coloring(); // 4. 汽车制造完毕 over(); } }
-
实际调用
public static void main(String[] args) { WhiteCarFactory whiteCarFactory=new WhiteCarFactory(); BlackCarFactory blackCarFactory=new BlackCarFactory(); // 生产白色汽车 whiteCarFactory.builderCar(); // 生产黑色汽车 blackCarFactory.builderCar(); }
输出结果:
功能虽然已经实现了,但是相信大家看到这里已经看出问题了,就是这两个类里面存在了大量的重复代码。而我们在实际软件开发过程中, 如果相同的一段代码复制过两次, 就需要对设计产生怀疑,架构师要明确地说明为什么相同的逻辑要出现两次或更多次。
很明显,我们需要把这些冗余的重复代码给优化掉,那么应该怎么设计呢?
模板方法模式实现
类图:
业务代码
-
这里先定义一个汽车的制造流程 抽象(模板)类
AbstractCarFactory
:/** * 汽车工厂 */ public abstract class AbstractCarFactory { void createFrame(){ System.out.println("制造汽车框架"); } void installComponent(){ System.out.println("安装零件"); } abstract void coloring(); void over(){ System.out.println("汽车制造完毕"); } void builderCar(){ // 1. 制造汽车框架 createFrame(); // 2. 安装汽车零件 installComponent(); // 3. 汽车喷漆,上色 coloring(); // 4. 汽车制造完毕 over(); } }
-
定义汽车工厂的实现类,生产白色汽车的工厂和生产黑色汽车的工厂
/** * 生产白色汽车的工厂 */ public class WhiteCarFactory extends AbstractCarFactory{ void coloring() { System.out.println("给汽车喷上白色的车漆"); } } /** * 生产黑色汽车的工厂 */ public class BlackCarFactory extends AbstractCarFactory{ void coloring() { System.out.println("给汽车喷上黑色的车漆"); } }
-
代码调用
public static void main(String[] args) { AbstractCarFactory whiteCarFactory=new WhiteCarFactory(); AbstractCarFactory blackCarFactory=new BlackCarFactory(); // 生产白色汽车 whiteCarFactory.builderCar(); // 生产黑色汽车 blackCarFactory.builderCar(); }
执行结果:
以上代码是不是看着很眼熟,特别是你如果看到过我的另外一篇描写抽象工厂模式的文章,对!你没看错,抽象工厂模式里面定义抽象工厂时,确实很大一部分就是使用的这个模板方法模式,而我们在项目实际开发时有意无意的代码中也会有模板方法模式的实践,只不过大多数情况下并没有认为这是个设计模式。
优点:
- 模板方法模式是通过把不变的行为挪到一个统一的父类,从而达到去除子类中重复代码的目的、
- 子类实现模板父类的某些细节,有助于模板父类的扩展
- 通过一个父类调用子类实现的操作,通过子类扩展增加新的行为,符合“开放-封闭原则”
缺点:
- 按照设计习惯,抽象类负责声明最抽象、最一般的事物属性和方法,实现类负责完成具体的事务属性和方法,但是模板方式正好相反,子类执行的结果影响了父类的结果,会增加代码阅读的难度
适用场景:
- 多个子类有共有的方法,并且逻辑基本相同
- 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现
- 重构时,模板方法是一个经常使用的方法,把相同的代码抽取到父类中,然后通过构造函数约束其行为