1、简介
定义:一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法中的某些特定步骤。
模板方法模式,一般是为了统一子类的算法实现步骤,所使用的一种手段或者说是方式。它在父类中定义一系列算法的步骤,而将具体的实现都推迟到子类。
最典型的形式就是一个接口,一个抽象父类,父类中会有一系列的抽象方法,而在子类中去实现这些方法。
类型:行为类模式
2、实例引入
背景:学校老师布置作业,老师布置作业,学生写作业,老师检查作业
定义一个抽象作业类
package com.designpattern.templete; /** * 类说明 :学校教师作业 */ public abstract class Homeork { final void workflow(){ //老师布置作业 this.assginHomework(); //学生 做 作业 this.doHomework(); //老师检查作业 this.checkHomework(); } //布置作业 void assginHomework(){ System.out.println("回家做课后习题,明天检查!"); } //学生 做 作业 abstract void doHomework(); //检查作业 void checkHomework(){ System.out.println("检查作业!"); } }
A同学完成写作业部分(只关心写作业的部分)
package com.designpattern.templete; /** * 类说明 :A同学完成作业类 */ public class StudentA extends Homeork{ @Override void doHomework() { //TODO 业务 System.out.println("A同学是这样完成作业的!"); } }
B同学完成写作业部分(只关心写作业的部分)
package com.designpattern.templete; /** * 类说明 :B同学完成作业类 */ public class StudentB extends Homeork{ @Override void doHomework() { // TODO 业务 System.out.println("B同学是这样完成作业的!"); } }
测试 A、B同学完成作业的过程
package com.designpattern.templete; /** * 类说明 :测试 */ public class Test { public static void main(String[] args) { //测试一次完成作业: 同学都是怎么样完成作业的 StudentA A = new StudentA(); A.workflow(); System.out.println("---------------------"); StudentB B = new StudentB(); B.workflow(); } }
结果
回家做课后习题,明天检查! A同学是这样完成作业的! 检查作业! --------------------- 回家做课后习题,明天检查! B同学是这样完成作业的! 检查作业!
3、解决的问题
上面的例子: 学校作业的流程都是一样的,只是学生做作业是五花八门的 ,所以把确定的部分提取到抽象父类中,可变的部分有子类完成;
学生不需要操作怎么布置作业,怎么检查作业,只需要把自己的任务 --- 写作业, 完成就行了。
4、应用场景
在多个子类拥有相同的方法,并且这些方法逻辑相同时,可以考虑使用模版方法模式。在程序的主框架相同,细节不同的场合下,也比较适合使用这种模式。
引用:大部分刚步入职场的毕业生应该都有类似的经历。一个复杂的任务,由公司中的牛人们将主要的逻辑写好,然后把那些看上去比较简单的方法写成抽象的,交给其他的同事去开发。这种分工方式在编程人员水平层次比较明显的公司中经常用到。比如一个项目组,有架构师,高级工程师,初级工程师,则一般由架构师使用大量的接口、抽象类将整个系统的逻辑串起来,实现的编码则根据难度的不同分别交给高级工程师和初级工程师来完成。怎么样,是不是用到过模版方法模式?
5、优缺点
优点:
容易扩展:一般来说,抽象类中的模版方法是不易反生改变的部分,而抽象方法是容易反生变化的部分,因此通过增加实现类一般可以很容易实现功能的扩展,符合开闭原则。
便于维护:对于模版方法模式来说,正是由于他们的主要逻辑相同,才使用了模版方法,假如不使用模版方法,任由这些相同的代码散乱的分布在不同的类中,维护起来是非常不方便的。
缺点:
子类的实现也可以影响父类中主逻辑的运行,在灵活的同时,由于子类影响到了父类,违反了里氏替换原则,也会给程序带来风险。这就对抽象类的设计有了更高的要求。
6、总结
一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现;
各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复;
控制子类的扩展;
在多个子类拥有相同的方法,并且这些方法逻辑相同时,可以考虑使用模版方法模式。在程序的主框架相同,细节不同的场合下,也比较适合使用这种模式。
PS:源码地址 https://github.com/JsonShare/DesignPattern/tree/master