定义:
模板模式是一种行为设计模式,使用了JAVA的继承机制,在抽象类中定义一个模板方法,该方法引用了若干个抽象方法(由子类实现)或具体方法(子类可以覆盖重写)。它的实现思路是,创建一个桩方法,并且定义一些步骤让子类来实现。模板方法定义了一个算法的执行步骤,或者说能够提供一种默认的实现,这种实现概括一部分子类或者全部子类的共同部分。
举一个例子帮助理解,假设提供一种造房子的算法。算法的步骤就是模拟造房子的过程:建地基、建支撑,最后添加墙和窗户 – 1. Fundation,2. Pillars,3. Walls,4. Windows。最重要的一点就是不能改变此建造过程,比如不可能在没用地基的时候就开始建造窗户。这个例子中,我们就创建了一个模板方法 – 将使用不同的方法完成对房子的建造。
为了确保子类不能重写(override)这个模板方法,应当使用final。
模式中的角色
抽象模板:定义了一个模板方法和若干抽象方法和具体方法.
具体模板:继承抽象模板类并实现抽象方法.
示例:模拟程序员的日常
抽象模板
package com.pichen.dp.behavioralpattern.templatemethod; public abstract class Day { public void getUp(){ System.out.println("get up~"); } public abstract void breakfast(); public abstract void goToWork(); public abstract void working(); public abstract void lunch(); public abstract void goHome(); public abstract void supper(); public void sleep(){ System.out.println("sleep~"); } //模板方法 public final void process(){ getUp(); breakfast(); goToWork(); working(); lunch(); working(); goHome(); supper(); sleep(); } }
具体模板
package com.pichen.dp.behavioralpattern.templatemethod; public class ProgrammerDay extends Day{ /** * @see com.pichen.dp.behavioralpattern.templatemethod.Day#breakfast() */ @Override public void breakfast() { System.out.println("breakfast:noodle~"); } /** * @see com.pichen.dp.behavioralpattern.templatemethod.Day#goToWork() */ @Override public void goToWork() { System.out.println("goToWork:drive car~"); } /** * @see com.pichen.dp.behavioralpattern.templatemethod.Day#working() */ @Override public void working() { System.out.println("working: coding~"); } /** * @see com.pichen.dp.behavioralpattern.templatemethod.Day#lunch() */ @Override public void lunch() { System.out.println("lunch: eat rice~"); } /** * @see com.pichen.dp.behavioralpattern.templatemethod.Day#goHome() */ @Override public void goHome() { System.out.println("goHome: walk~"); } /** * @see com.pichen.dp.behavioralpattern.templatemethod.Day#supper() */ @Override public void supper() { System.out.println("supper: rice~"); } }
客户端
package com.pichen.dp.behavioralpattern.templatemethod; public class Main { public static void main(String[] args) { Day programmerDay = new ProgrammerDay(); programmerDay.process(); } }
结果
get up~ breakfast:noodle~ goToWork:drive car~ working: coding~ lunch: eat rice~ working: coding~ goHome: walk~ supper: rice~ sleep~
模版方法模式的结构
模版方法模式由一个抽象类和一个(或一组)实现类通过继承结构组成,抽象类中的方法分为三种:
- 抽象方法:父类中只声明但不加以实现,而是定义好规范,然后由它的子类去实现。
- 模版方法:由抽象类声明并加以实现。一般来说,模版方法调用抽象方法来完成主要的逻辑功能,并且,模版方法大多会定义为final类型,指明主要的逻辑功能在子类中不能被重写。
- 钩子方法:由抽象类声明并加以实现。但是子类可以去扩展,子类可以通过扩展钩子方法来影响模版方法的逻辑。
- 抽象类的任务是搭建逻辑的框架,通常由经验丰富的人员编写,因为抽象类的好坏直接决定了程序是否稳定性。
实现类用来实现细节。抽象类中的模版方法正是通过实现类扩展的方法来完成业务逻辑。只要实现类中的扩展方法通过了单元测试,在模版方法正确的前提下,整体功能一般不会出现大的错误。
优点
容易扩展。一般来说,抽象类中的模版方法是不易反生改变的部分,而抽象方法是容易反生变化的部分,因此通过增加实现类一般可以很容易实现功能的扩展,符合开闭原则。
便于维护。对于模版方法模式来说,正是由于他们的主要逻辑相同,才使用了模版方法,假如不使用模版方法,任由这些相同的代码散乱的分布在不同的类中,维护起来是非常不方便的。
比较灵活。因为有钩子方法,因此,子类的实现也可以影响父类中主逻辑的运行。但是,在灵活的同时,由于子类影响到了父类,违反了里氏替换原则,也会给程序带来风险。这就对抽象类的设计有了更高的要求。
在多个子类拥有相同的方法,并且这些方法逻辑相同时,可以考虑使用模版方法模式。在程序的主框架相同,细节不同的场合下,也比较适合使用这种模式