模板方法模式 Template Method Pattern 定义如下:
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
先定义抽象模板类:
/** * 抽象模板类 * 为了防止恶心操作,模板方法都会加上final关键字,不允许覆盖 * * @author XiongNeng * @version 1.0 * @since 13-5-22 */ public abstract class AbstractTemplate { // 基本方法 protected abstract void doSomething(); // 基本方法 protected abstract void doAnything(); // 模板方法 public final void templateMethod() { // 调用基本方法,完成相关的业务逻辑 this.doSomething(); this.doAnything(); } }
然后是实现类:
public class ConcreteClass1 extends AbstractTemplate { @Override protected void doSomething() { System.out.println("class1 doSomething..."); } @Override protected void doAnything() { System.out.println("class1 doAnything..."); } }
public class ConcreteClass2 extends AbstractTemplate { @Override protected void doSomething() { System.out.println("class2 doSomething..."); } @Override protected void doAnything() { System.out.println("class2 doAnything..."); } }
注意:
抽象模板中的基本方法尽量设计为protected,符合迪米特法则,不需要暴露的属性或方法尽量不要设置为protected,更不要设置为public。实现类若非必要,尽量不要扩大父类中的访问权限。
模板方法的优点:
1,封装不变部分,扩展可变部分
2,提取公共部分代码,便于维护
3,抽象父类负责控制行为,而具体子类负责实现行为,相当于一个司令负责调度下面的部署作战方案,具体怎样去执行这个命令达到目的(到底是夜袭还是埋伏还是奇袭),就是下属决定的了。
模板方法的缺点:
抽象类定义了部分抽象方法,由子类实现,子类执行结果影响了父类结果,也就是子类对父类产生了影响,这在负责项目中,会给代码阅读带来一定的难度,让新手感到不适。
模板方法使用场景:
1,多个子类有公有方法,并且逻辑基本相同
2,重要、负责的算法,可以把核心算法设计为模板方法,周边的相关细节功能由子类实现
3,重构时候,模板方法是一个经常使用的模式,把相同代码抽取到父类中,然后通过钩子函数(见 模板方法模式的扩展)约束其行为
模板方法的扩展:
public abstract class AbstractTemplate { // 基本方法 protected abstract void doSomething(); // 基本方法 protected abstract void doAnything(); // 模板方法 public final void templateMethod() { // 调用基本方法,完成相关的业务逻辑 this.doSomething(); this.doAnything(); if (hookFlag()) { System.out.println("----Oh yes, hookFlag..."); } else { System.out.println("----Oh no, hookFlag..."); } } // 钩子方法 protected abstract boolean hookFlag(); }
public class ConcreteClass1 extends AbstractTemplate { private boolean hookFlag; @Override protected void doSomething() { System.out.println("class1 doSomething..."); } @Override protected void doAnything() { System.out.println("class1 doAnything..."); } @Override protected boolean hookFlag() { return hookFlag; } public void setHookFlag(boolean hookFlag) { this.hookFlag = hookFlag; } }
外界条件的改变可以影响到模板方法的执行。我们抽象类中hookFlag()方法返回值影响了模板方法执行结果,该方法叫钩子方法。有了钩子方法模板方法才算完美。
最佳实践:
父类建立框架,子类在重写了父类部分的方法后,再调用从父类继承的方法,也就是模板方法,产生不同的结果,而这正是模板方法模式。这也可以理解为父类调用了子类的方法,你修改了子类,影响了父类的行为,曲线救国的方式实现了父类依赖子类的场景,模板方法就是这种效果。
模板方法在一些开源框架中应用非常多,它提供了一个抽象类,然后开源框架写了一堆子类。
如果你需要扩展功能,可以继承这个抽象类,然后覆写protected方法,在然后就是调用一个类似于execute的模板方法,就完成了你的扩展开放,非常容易扩展的一种模式。
本人博客已搬家,新地址为:http://yidao620c.github.io/