设计模式-模板方法模式


一、什么是模板方法模式?

     模板方法:定义了一套流程算法骨架,将一些固定的算法由抽象类定义,可变的部分延迟到子类中实现,同时可以定义一些钩子方法控制抽象类的操作。
模式的结构
1、抽象类(模板方法、抽象方法、具体方法、钩子方法)
     模板方法:定义具体操作流程,按某种顺序调用抽象方法、具体方法和钩子方法。
     抽象方法:需要子类实现的方法。
     具体方法:个流程相同的方法,由抽象类统一实现的。子类可以对其进行重写。
2、具体实现类
     实现抽象类中的抽象方法。
     AbstractClass为抽象类,templateMethod()为抽象方法里面调用了具体方法(specificMethod())和抽象方法(abstractMethod()),SubClass为AbstractClass的子类实现了实现了抽象方法。ClientClass为客户类用于调用抽象类的模板方法。
UML图如下:
template_method_UML
模板方法模式的优缺点
优点:
     1、将不变的部分封装到父类,可变部分由子类进行实现,便于子类进行扩展。
     2、将公用部分统一由父类实现,提高了代码的复用性。
缺点:
     1、每个不同的实现都要增加类的个数,增加了系统的复杂程度,也增加了代码阅读的难度。
     2、由于继承关系,父类增加抽象方法所有的子类都需要进行实现,所有子类都需要进行修改。

二、模板方法模式应用实例

     每个人的一天都是不同的,但具有相同部分例如起床、洗漱、吃早饭、完成上午的工作、午休、完成下午的工作、下班后的自由时间、晚上休息等。每天不同的地方在于上午的工作、下午的工作、下班后的自由时间所做的事情不同,其他基本是一样的。以一天为例实现一个简单的模板方法模式。
代码如下:

// 测试类
public class TestOneDay {
    public static void main(String[] args) {
        System.out.println("创建学生一天实例");
        OneDayAbstract studentDay = new StudentDay();
        System.out.println("执行学生的一天");
        studentDay.run();
        
        System.out.println("创建程序员一天实例");
        OneDayAbstract programmerDay = new ProgrammerDay();
        System.out.println("执行程序员的一天");
        programmerDay.run();
    }
}

/**
* 一天(抽象类)
*/
public abstract class OneDayAbstract {

    // 执行一天要做的事(模板方法 调用具体方法、抽象方法)
    public void run(){
        System.out.println("新的一天开始了!!!!");
        System.out.println("时间:07:00");
        up();
        System.out.println("时间:09:00");
        work1();
        System.out.println("时间:11:30");
        noonBreak();
        System.out.println("时间:13:30");
        work2();
        System.out.println("时间:18:00");
        anything();
        System.out.println("时间:23:00");
        sleep();
        System.out.println("新的一天结束了!!!!");
    }
	// 具体方法 早起做的事
    public void up(){
        System.out.println("起床!!!");
        System.out.println("洗漱!!");
        System.out.println("吃早饭!");
    }

    // 抽象方法 子类需要实现 完成上午的工作
    abstract void work1();

	// 具体方法 午休
    public void noonBreak(){
        System.out.println("午休~");
    }

    // 抽象方法 子类需要实现 完成下午的工作
    abstract void work2();

    // 抽象方法 子类需要实现 下班后可以做任意事
    abstract void anything();
	// 具体方法 一天结束休息
    public void sleep(){
        System.out.println("休息!!!!!");
    }
}

/**
* 程序员的一天
*/
public class ProgrammerDay extends OneDayAbstract {

    @Override
    void work1() {
        System.out.println("上午-敲代码!!!!");
    }

    @Override
    void work2() {
        System.out.println("下午-敲代码!!!!");
    }

    @Override
    void anything() {
        System.out.println("下班?不可能的。加班继续敲代码!!!!");
    }
}

/**
 * 学生的一天
 */
public class StudentDay extends OneDayAbstract {
    @Override
    void work1() {
        System.out.println("上数学、语文、英语课!!!");
    }

    @Override
    void work2() {
        System.out.println("上物理、化学、生物课!!!");
    }

    @Override
    void anything() {
        System.out.println("晚自习拼命做题!!!");
    }
}

执行结果如下:
程序执行结果
     以学生和程序员为例实现了一天的抽象类。如果需要再添加一类人的一天则只需要集成抽象类并实现抽象方法就可以完成了,提高了开发效率。

模板方法模式拓展
     抽象类中还有一类方法叫钩子方法,钩子方法一般是指判断的逻辑方法或者空方法由子类进行实现的,下面说明下钩子方法的使用。
一天的需求有变动,由于项目近期要上线需要赶工,程序员的午休时间取消了(程序员:mmp)。这时可以在抽象类的模板方法中增加判断逻辑。代码如下:

// 其他方法不变 只贴出了修改的方法
public abstract class OneDayAbstract {

    // 修改模板方法中逻辑 午休增加判断
    public void run(){
        System.out.println("新的一天开始了!!!!");
        System.out.println("时间:07:00");
        up();
        System.out.println("时间:09:00");
        work1();
        System.out.println("时间:11:30");
        // 判断是否需要午休
        if(haveNoonBreak()){
            noonBreak();
        }
        System.out.println("时间:13:30");
        work2();
        System.out.println("时间:18:00");
        anything();
        System.out.println("时间:23:00");
        sleep();
        System.out.println("新的一天结束了!!!!");
    }

    // 是否需要午休 默认为true 需要午休
    public boolean haveNoonBreak(){
        return true;
    }
}

/**
* 程序员的一天
*/
public class ProgrammerDay extends OneDayAbstract {

    @Override
    void work1() {
        System.out.println("上午-敲代码!!!!");
    }

    @Override
    void work2() {
        System.out.println("下午-敲代码!!!!");
    }

    @Override
    void anything() {
        System.out.println("下班?不可能的。加班继续敲代码!!!!");
    }

    // 覆盖方法 修改返回值为false 不需要午休
    @Override
    public boolean haveNoonBreak(){
        return false;
    }
}

修改后执行的结果如下:result2
增加了钩子方法后一般不会影响原有的实现类,因为钩子方法是默认实现的返回值为true。当返回值为true是模板方法的逻辑也没有发生变化,只有子类修改返回值为false时模板方法的逻辑才会发生变化。当然钩子的使用一般在程序设计时就已经添加在抽象类中了。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值