设计模式-模板方法模式

概述:


定义一个操作中的算法的骨架,而将步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构,即可重定义算法的某些特定步骤。

模板方法非常常见,对创建框架来说,由框架控制如何做事情,而由你(使用这个框架的人)指定框架算法中每个步骤的细节。(可以想想单元测试的框架JUnit的实现。)

模式中的角色:


  1. 抽象类(AbstractClass):实现了模板方法,定义了算法的骨架。
  2. 具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法。

模板方法模式代码实现(Java):


举个例子,以准备去学校所要做的工作(prepareGotoSchool)为例,假设需要分三步:穿衣服(dressUp),吃早饭(eatBreakfast),带上东西(takeThings)。学生和老师要做得具体事情肯定有所区别。

package com.template.pattern;

/**
 * 抽象类AbstractClass
 */
public abstract class AbstractPerson {
    // 抽象类定义整个流程骨架
    public void prepareGotoSchool() {
        dressUp();
        eatBreakfast();
        takeThings();
    }

    // 以下是不同子类根据自身特性完成的具体步骤
    protected abstract void dressUp();

    protected abstract void eatBreakfast();

    protected abstract void takeThings();
}

package com.template.pattern.vo;

import com.template.pattern.AbstractPerson;

/**
 * 具体类ConcreteClass:学生
 */
public class StudentVo extends AbstractPerson {
    @Override
    protected void dressUp() {
        System.out.println("穿校服");
    }

    @Override
    protected void eatBreakfast() {
        System.out.println("吃妈妈做好的早饭");
    }

    @Override
    protected void takeThings() {
        System.out.println("背书包,带上家庭作业和红领巾");
    }
}

/**
 * 具体类ConcreteClass:老师,做的事情不一样,但是步骤(模版方法)一样
 */
public class TeacherVo extends AbstractPerson {
    @Override
    protected void dressUp() {
        System.out.println("穿工作服");
    }

    @Override
    protected void eatBreakfast() {
        System.out.println("做早饭,照顾孩子吃早饭");
    }

    @Override
    protected void takeThings() {
        System.out.println("带上昨晚准备的考卷");
    }
}

/**
 * Main方法
 */
public class MainMethod {

    /**
     * 调用
     */
    public static void main(String[] args) {
        System.out.println("学生:");
        StudentVo sVo = new StudentVo();
        sVo.prepareGotoSchool();
        // ---------------------------
        System.out.println("老师:");
        TeacherVo tVo = new TeacherVo();
        tVo.prepareGotoSchool();

        // 或者
        // AbstractPerson aSVo = new StudentVo();
        // aSVo.prepareGotoSchool();
        // AbstractPerson aTVo = new TeacherVo();
        // aTVo.prepareGotoSchool();
    }
}

对模板方法进行挂钩:


钩子(hook)是一种被声明在抽象类中的方法,但只有空的或者默认的实现

钩子的存在,可以让子类有能力对算法的不同点进行挂钩。要不要挂钩,由子类自行决定。

某些步骤是可选的,所以可以将这些步骤实现成钩子,而不是实现成抽象方法,这样就可以让抽象类的子类的负荷减轻。

比如,也可以利用钩子做条件控制,影响抽象类中的算法流程:钩子方法在抽象类中有默认实现返回true,放在抽象类的if条件语句中,子类可以覆盖也可以不覆盖这个钩子方法。

具体实现可以参考下面的url,就是写了个方法,返回true,false,表示是否执行某个方法,进行判断

JUnit中的模板方法模式体现:


以JUnit3为例,JUnit3中,所有的测试类都要继承于TestCase,这个基类中规定了方法调用的顺序,所以每次测试时都是先执行setUp(),再执行测试方法,最后执行tearDown()。

可以查看JUnit3的源代码:

/**
 * Runs the bare test sequence.
 * @exception Throwable if any exception is thrown
 */
public void runBare() throws Throwable{
    setUp();
    try{
        runTest();
    } finally {
        tearDown();
    }
}

模式总结


  1. 优点
    • 模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。
    • 子类实现算法的某些细节,有助于算法的扩展。
    • 通过一个父类调用子类实现的操作,通过子类扩展增加新的行为,符合“开放-封闭原则”。
    • ——————————————————————–
    • 容易扩展。一般来说,抽象类中的模版方法是不易反生改变的部分,而抽象方法是容易反生变化的部分,因此通过增加实现类一般可以很容易实现功能的扩展,符合开闭原则。
    • 便于维护。对于模版方法模式来说,正是由于他们的主要逻辑相同,才使用了模版方法,假如不使用模版方法,任由这些相同的代码散乱的分布在不同的类中,维护起来是非常不方便的。
    • 比较灵活。因为有钩子方法,因此,子类的实现也可以影响父类中主逻辑的运行。但是,在灵活的同时,由于子类影响到了父类,违反了里氏替换原则,也会给程序带来风险。这就对抽象类的设计有了更高的要求。
  2. 缺点
    • 每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。
  3. 适用场景
    • 在某些类的算法中,用了相同的方法,造成代码的重复。
    • 控制子类扩展,子类必须遵守算法规则。

代码下载


模板模式TemplatePattern - 8KB


参考:
- http://www.cnblogs.com/mengdd/archive/2013/04/14/3020577.html
- http://www.cnblogs.com/mengdd/archive/2013/05/04/3059706.html
- http://rjx2008.iteye.com/blog/340362
- http://blog.csdn.net/zhengzhb/article/details/7405608


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值