模板方法模式定义
模板方法模式定义:定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法模式非常简单,仅仅使用了Java的继承机制,但它是一个应用非常广泛的模式。
模板方法模式算法框架
模板方法模式的通用类图如图所示。包含两个角色,一个是抽象模板类,一个是具体模板类。
其中AbstractClass是抽象模板类,它的方法分为两类:
- 基本方法
基本方法也叫做基本操作,是由子类实现的方法,并且在模板方法被调用。
- 模板方法
可以有一个或几个,一般是一个具体方法,也就是一个框架,实现对基本方法的调度,完成固定的逻辑。 -
注意:为了防止恶意的操作,一般模板方法都加上final关键字,不允许被覆写。
public abstract class AbstractClass { //基本方法 protected abstract void doSomething(); //基本方法 protected abstract void doAnything(); //模板方法 public void templateMethod(){ /* * 调用基本方法,完成相关的逻辑 */ this.doAnything(); this.doSomething(); } }
具体模板类继承抽象模板类,如下的ConcreteClass1和ConcreteClass2属于具体模板,实现父类所定义的一个或多个抽象方法,也就是父类定义的基本方法在子类中得以实现。
public class ConcreteClass1 extends AbstractClass{ @Override protected void doSomething() { //业务逻辑处理 } @Override protected void doAnything() { //业务逻辑处理 } } public class ConcreteClass2 extends AbstractClass{ @Override protected void doSomething() { //业务逻辑处理 } @Override protected void doAnything() { //业务逻辑处理 } }
场景类如下所示:
public class Client { public static void main(String[] args){ AbstractClass class1=new ConcreteClass1(); AbstractClass class2=new ConcreteClass2(); //调用模板方法 class1.templateMethod(); class2.templateMethod(); } }
注意:抽象模板中的基本方法尽量设计为protected类型,符合迪米特法则,不需要暴露的属性或方法尽量不要设置为protected类型。实现类若非必要,尽量不要扩大父类中的访问权限。
模板方法模式优缺点
- 优点
封装不变部分,扩展可变部分:把认为是不变部分的算法封装到父类实现,而可变部分的则可以通过继承来继续扩展。
提取公共部分代码,便于维护。
行为由父类控制,子类实现:基本方法是由子类实现的,因此子类可以通过扩展的方式增加相应的功能,符合开闭原则。 - 缺点
按照我们的设计习惯,抽象类负责声明最抽象,最一般的事物属性和方法,实现类完成具体的事物属性和方法。但是模板方法模式却颠倒了,抽象类定义了部分抽象方法,由子类实现,子类执行的结果影响了父类的结果,也就是子类对父类产生了影响。 -
模板方法模式的使用场景
模板方法模式就是在模板方法中按照一定的规则和顺序调用基本方法。
- 多个子类有公有的方法,并且逻辑基本相同时。
- 重要,复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
- 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
-
模板方法模式扩展
在抽象类中增加一个实现方法isContinue,确定是否需要执行某个基本方法,由各个实现类覆写该方法,也可以默认不覆写。
public abstract class AbstractClass { //基本方法 protected abstract void doSomething(); //基本方法 protected abstract void doAnything(); //模板方法 public void templateMethod(){ /* * 调用基本方法,完成相关的逻辑 */ if(this.isContinue()){ this.doAnything(); this.doSomething(); } } //钩子方法 约束父类行为 protected boolean isContinue() { return true; } }
具体类修改如下:
public class ConcreteClass1 extends AbstractClass { // 外界条件 protected boolean isContinue = true; @Override protected void doSomething() { // 业务逻辑处理 } @Override protected void doAnything() { // 业务逻辑处理 } @Override protected boolean isContinue() { return isContinue; } public void setContinue(boolean isContinue) { this.isContinue = isContinue; } } public class ConcreteClass2 extends AbstractClass{ @Override protected void doSomething() { //业务逻辑处理 } @Override protected void doAnything() { //业务逻辑处理 } protected boolean isContinue() { return false; } }
在抽象类中增加了一个控制变量isContinue,在模板方法中来判断是否需要执行基本方法。也就是外界条件改变,影响到模板方法的执行。模板方法中调用的isContinue方法的返回值影响了模板方法的执行结果,该方法就叫做钩子方法。钩子方法扩展了模板方法模式,由子类的一个方法返回值决定公共部分的执行结果。