模版方法模式

作者: 我可能是个假开发 | 来源:发表于2019-01-09 15:56 被阅读15次

模版方法模式

一、什么是模版方法模式

模板模式 :解决某类事情的步骤有些是固定的,有些是会发生变化的,那么这时候我们可以为这类事情提供一个模板代码,从而提高效率。

1.生活中的模版:

办理银行业务:

  1. 进门取号
  2. 填写单据(每个客户填写的单据都不一样,因业务不同而不同)
  3. 等待叫号
  4. 窗口办理

二、如何实现模版方法模式

1.模版方法模式的实现要素

准备一个抽象类,将部分逻辑以具体方法的形式实现,然后声明一些抽象方法交由子类实现剩余逻辑,用钩子方法给予子类更大的灵活性。最后将方法汇总构成一个不可改变的模版方法。

2.模版模式的步骤

  1. 先写出解决该类事情其中 的一件的解决方案。
  2. 分析代码,把会发生变化的代码抽取出来独立成一个方法。把该方法描述成一个抽象的方法。
  3. 使用final修饰模板方法,防止别人重写你的模板方法。

3.具体实现

案例一:编写一个计算程序运行时间的模板。

  • 记录开始时间
  • 代码的执行过程
  • 记录结束时间
  • 运行时间=结束时间-开始时间

抽象基类:

abstract class MyRuntime{
    
    public final void getTime(){
        long startTime = System.currentTimeMillis();    //记录开始的时间
        code();
        long endTime = System.currentTimeMillis();  //记录结束的时间.
        System.out.println("运行时间 :"+ (endTime-startTime));
    }

    public abstract void code();
}

具体子类:

class Demo extends MyRuntime
{
    public static void main(String[] args) 
    {
        Demo d = new Demo();
        d.getTime();
    }

    //code方法内部就写要计算运行时间的代码;
    public  void code(){
        int i = 0;
        while(i<100){
            System.out.println("i="+i);
            i++;
        }
    }
}

案例二:饮料的制法:

把水煮沸(boilWater)
冲饮料(brew)
把饮料倒进杯子(pourInCup)
加调味料(addCondiments)

抽象基类:Drinks

package com.hcx.pattern.template;

/**
 * 抽象基类,为所有子类提供一个算法框架
 * 饮料
 * @author HCX
 *
 */
public abstract class Drinks {
    
    /**
     * 使用final修饰,防止子类改变模版方法
     * 制备饮料的模版方法
     * 封装了所有子类共同遵循的算法框架
     */
    public final void prepareDrinksTemplate(){
        //步骤一:把水煮沸
        boilWater();
        //步骤二:冲饮料
        brew();
        //步骤三:把饮料倒进杯子
        pourInCup();
        //步骤四:加调味料
        addCondiments();
        
    }

    
    /**
     * 基本方法:把水煮沸
     * 对所有子类,是一个共同的行为,不需要向子类开放;将变化的东西放在高层代码中。
     */
    private void boilWater() {
        System.out.println("把水煮沸");
    }
    /**
     * 基本方法:将饮料倒入杯中
     */
    private void pourInCup() {
        System.out.println("将饮料倒入杯中");
    }

    /**
     * 不同的情况,具体的实现不同,设计为抽象方法,需要在子类中可见,以便子类复写,提供具体的实现。
     * 抽象的基本方法:加入调料
     */
    protected abstract void addCondiments();
    /**
     * 抽象的基本方法:泡饮料
     */
    protected abstract void brew();

}

具体子类:Coffee

package com.hcx.pattern.template;

/**
 * 具体子类,提供了咖啡制备的具体实现
 * @author HCX
 *
 */
public class Coffee extends Drinks {

    @Override
    protected void brew() {
        System.out.println("用沸水冲泡咖啡");
    }
    
    @Override
    protected void addCondiments() {
        System.out.println("加入糖和牛奶");
    }
}

具体子类:OrangeJuice

package com.hcx.pattern.template;

/**
 * 具体子类,提供了橙汁的具体实现
 * @author HCX
 *
 */
public class OrangeJuice extends Drinks{

    @Override
    protected void brew() {
        System.out.println("准备橙子和榨汁机,把橙子丢入机器中榨汁");
    }
    
    @Override
    protected void addCondiments() {
        System.out.println("加入糖浆");
    }

}

测试:

package com.hcx.pattern.template;

public class DrinksTest {
    
    public static void main(String[] args) {
        System.out.println("咖啡制备中");
        Drinks drinks = new Coffee();
        drinks.prepareDrinksTemplate();
        System.out.println("咖啡好了");
        
        System.out.println("*************************************");
        
        System.out.println("橙汁制备中");
        Drinks drinks2 = new OrangeJuice();
        drinks2.prepareDrinksTemplate();
        System.out.println("橙汁好了");
    }

}

结果:

咖啡制备中
把水煮沸
用沸水冲泡咖啡
将饮料倒入杯中
加入糖和牛奶
咖啡好了
*************************************
橙汁制备中
把水煮沸
准备榨汁机和榨汁机,把橙子丢入机器中榨汁
将饮料倒入杯中
加入糖浆
橙汁好了

使用钩子方法使代码更灵活:

在制备橙汁时,不想加入糖浆;

修改Drinks类,在加入调味料的步骤进行判断,编写钩子函数:

package com.hcx.pattern.template;

/**
 * 抽象基类,为所有子类提供一个算法框架
 * 饮料
 * @author HCX
 *
 */
public abstract class Drinks {
    
    /**
     * 使用final修饰,防止子类改变模版方法
     * 制备饮料的模版方法
     * 封装了所有子类共同遵循的算法框架
     */
    public final void prepareDrinksTemplate(){
        //步骤一:把水煮沸
        boilWater();
        //步骤二:冲饮料
        brew();
        //步骤三:把饮料倒进杯子
        pourInCup();
        
        //步骤四:加调味料
        if(wantCondiments()){
            addCondiments();
        }
    }

    /**
     * Hook:钩子函数,提供一个默认或空的实现
     * 具体的子类可以自行决定是否挂钩以及如何挂钩,即是否重写父类的钩子函数
     * 根据个人喜好,是否加入调料
     * @return
     */
    protected boolean wantCondiments() {
        return true;
    }


    /**
     * 基本方法:把水煮沸
     * 对所有子类,是一个共同的行为,不需要向子类开放;将变化的东西放在高层代码中。
     */
    private void boilWater() {
        System.out.println("把水煮沸");
    }
    /**
     * 基本方法:将饮料倒入杯中
     */
    private void pourInCup() {
        System.out.println("将饮料倒入杯中");
    }

    /**
     * 不同的情况,具体的实现不同,设计为抽象方法,需要在子类中可见,以便子类复写,提供具体的实现。
     * 抽象的基本方法:加入调料
     */
    protected abstract void addCondiments();
    /**
     * 抽象的基本方法:泡饮料
     */
    protected abstract void brew();
}

在OrangeJuice中重写钩子函数时:

package com.hcx.pattern.template;

/**
 * 具体子类,提供了橙汁的具体实现
 * @author HCX
 *
 */
public class OrangeJuice extends Drinks{

    @Override
    protected void brew() {
        System.out.println("准备橙子和榨汁机,把橙子丢入机器中榨汁");
    }
    
    @Override
    protected void addCondiments() {
        System.out.println("加入糖浆");
    }
    
    /**
     * 重写父类的钩子方法
     * 不加入任何调料,纯正的橙汁
     */
    @Override
    protected boolean wantCondiments() {
        return false;
    }
}

测试类打印结果:

咖啡制备中
把水煮沸
用沸水冲泡咖啡
将饮料倒入杯中
加入糖和牛奶
咖啡好了
*************************************
橙汁制备中
把水煮沸
准备橙子和榨汁机,把橙子丢入机器中榨汁
将饮料倒入杯中
橙汁好了

总结:

模版模式总结.png

三、模版方法模式的适用场景及优缺点

适用场景:

  • 算法或操作遵循相似的逻辑
  • 重构时(把相同的代码抽取到父类中)
  • 重要、复杂的算法,核心算法设计为模版算法

优点:

  • 封装性好
  • 复用性好
  • 屏蔽细节
  • 便于维护

缺点:

  • 单继承

四、实例分析

分析处理各种日志

需求分析:

日志需求分析.png

可抽象为如下的步骤:

  • 获得文件
  • 打开文件
  • 读取日志结构
  • 处理单行日志(会变化的部分,延迟到子类实现)
  • 清理工作

根据不同的情况,在变化部分的前后提供一些函数来提供扩展。

相关文章

  • 设计模式-模版方法模式

    设计模式-模版方法模式 定义 模版方法模式(Template Method Pattern)又叫模版模式,是指定义...

  • 设计模式[14]-模版方法模式-Template Method

    1.模版方法模式简介 模版方法模式(Template Method Pattern)是行为型(Behavioral...

  • 设计模式之模版方法模式

    模版方法模式 模版方法是一种只需使用继承就可以实现的非常简单的模式模版方法模式由两部分结构组成,第一部分是抽象父类...

  • 设计模式之模版方法模式

    模版方法模式 模版方法是一种只需使用继承就可以实现的非常简单的模式模版方法模式由两部分结构组成,第一部分是抽象父类...

  • 设计模式之Template模式(模版模式)

    1 模式简介 1.1 模版方法模式的定义:模版方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模...

  • 模版方法模式

    通俗讲,模版模式就是将通用的上升到父类中,个性化的功能由各个子类完成.代码的复用是模版模式主要解决的.

  • 模版方法模式

    模版方法模式 定义:定义一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算...

  • 模版方法模式

  • 模版方法模式

  • 模版方法模式

    模版方法模式(定义):通过把相同的方法移动到父类,去除子类中的重复代码,提供一个很好的代码复用平台

网友评论

    本文标题:模版方法模式

    本文链接:https://www.haomeiwen.com/subject/tidgrqtx.html