一、含义
定义一个算法中的操作框架,而将一些步骤延迟到子类中。使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤,不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。
二、模式中的角色
抽象类(AbstractClass):实现了模板方法,定义了算法的骨架。
具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法
三、类图及源码
模板方法模式的通用类图非常简单,仅仅使用了Java的继承机制,但它是一个非常广泛的模式。其类图如下,其中AbstractClass叫做抽象模板,它的方法分为两类:
- 基本方法:是由子类实现的方法,并且在模板方法被调用。(一般都加上final关键字,防止被覆写)
- 模板方法:可以有一个或几个,一般是一个具体方法,也就是一个框架,实现对基本方法的调用,完成固定的逻辑。(抽象模板中的基本方法尽量设计为protected类型,符合迪米特法则,不需要暴露的属性或方法尽量不要设置为protected类型。实现类若非必要,尽量不要扩大父类中的访问权限)
上述通用类图的源码如下:
1 public abstract class AbstractClass { 2 protected abstract void doAnything(); 3 protected abstract void doSomething(); 4 public final void templateMethod(){ 5 /* 6 * 调用基本方法,完成相关的逻辑 7 */ 8 this.doAnything(); 9 this.doSomething(); 10 } 11 } 12 public class ConcreteClass1 extends AbstractClass { 13 14 @Override 15 protected void doAnything() { 16 // TODO Auto-generated method stub 17 //子类实现具体 18 } 19 20 @Override 21 protected void doSomething() { 22 // TODO Auto-generated method stub 23 } 24 } 25 public class ConcreteClass2 extends AbstractClass { 26 27 @Override 28 protected void doAnything() { 29 // TODO Auto-generated method stub 30 //子类实现具体 31 } 32 33 @Override 34 protected void doSomething() { 35 // TODO Auto-generated method stub 36 } 37 }
四、优缺点
1、模板方法模式的优点
- 封装不变部分,扩展可变部分。把认为不变部分的算法封装到父类中实现,而可变部分的则可以通过继承来继续扩展。
- 提取公共部分代码,便于维护。
- 行为由父类控制,子类实现。
2、模板方法模式的缺点
按照设计习惯,抽象类负责声明最抽象、最一般的事物属性和方法,实现类负责完成具体的事务属性和方法,但是模板方式正好相反,子类执行的结果影响了父类的结果,会增加代码阅读的难度。
五、使用场景
- 多个子类有共有的方法,并且逻辑基本相同
- 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现
- 重构时,模板方法是一个经常使用的方法,把相同的代码抽取到父类中,然后通过构造函数约束其行为
六、实例
以准备去学校所要做的工作(prepareGotoSchool)为例,假设需要分三步:穿衣服(dressUp),吃早饭(eatBreakfast),带上东西(takeThings)。学生和老师要做得具体事情肯定有所区别。
抽象类AbstractClass
1 public abstract class AbstractPerson{ 2 //抽象类定义整个流程骨架 3 public void prepareGotoSchool(){ 4 dressUp(); 5 eatBreakfast(); 6 takeThings(); 7 } 8 //以下是不同子类根据自身特性完成的具体步骤 9 protected abstract void dressUp(); 10 protected abstract void eatBreakfast(); 11 protected abstract void takeThings(); 12 }
具体类ConcreteClass
1 public class Student extends AbstractPerson{ 2 @Override 3 protected void dressUp() { 4 System.out.println(“穿校服"); 5 } 6 @Override 7 protected void eatBreakfast() { 8 System.out.println(“吃妈妈做好的早饭"); 9 } 10 11 @Override 12 protected void takeThings() { 13 System.out.println(“背书包,带上家庭作业和红领巾"); 14 } 15 }
1 public class Teacher extends AbstractPerson{ 2 @Override 3 protected void dressUp() { 4 System.out.println(“穿工作服"); 5 } 6 @Override 7 protected void eatBreakfast() { 8 System.out.println(“做早饭,照顾孩子吃早饭"); 9 } 10 11 @Override 12 protected void takeThings() { 13 System.out.println(“带上昨晚准备的考卷"); 14 } 15 }
测试类:
1 public class Client { 2 public static void main(String[] args) { 3 Student student = new Student() 4 student.prepareGotoSchool(); 5 6 Teacher teacher = new Teacher() 7 teacher.prepareGotoSchool(); 8 } 9 }