1

时间:2017年09月02日星期六
说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com
教学源码:https://github.com/zccodere/s...
学习源码:https://github.com/zccodere/s...

第一章:模版模式简介

1-1 简介

内容介绍

什么是模版方法模式
如何实现模版方法模式
模版方法模式的特点
模版方法模式在项目中的应用

模板方法模式

定义了一个操作算法框架,而将一些步骤延迟到子类中实现,
使得子类在不改变一个算法结构的同时就重新定义该算法的某些特定步骤。

案例介绍:饮料机配置模版

1.把水煮沸(boilWater)
2.*泡饮料(brew)*
3.把饮料倒进杯子(pourInCup)
4.*加调味料(addCondiments)*

第二章:模版模式实现

2-1 基本框架

代码编写

1.编写RefreshBeverage类

package com.myimooc.designpattern.c8template;

/**
 * @title 模版模式
 * @describe 抽象基类,为所有子类提供一个算法框架。提神饮料
 * @author zc
 * @version 1.0 2017-09-02
 */
public abstract class RefreshBeverage {
    
    /**
     * 制备饮料的模版方法
     * 封装了所有子类共同遵循的算法框架
     */
    public final void prepareBeverageTemplate(){
        // 步骤1 将水煮沸
        boilWater();
        
        // 步骤2 泡制饮料
        brew();
        
        // 步骤3 将饮料倒入杯中
        pourInCup();
        
        // 步骤4 加入调味料
        addCondiments();
    }
    
    /**
     * 基本方法,将水煮沸
     */
    private void boilWater() {
        System.out.println("将水煮沸");
    }
    
    /**
     * 基本方法,将饮料倒入杯中
     */
    private void pourInCup() {
        System.out.println("将饮料倒入杯中");
        
    }
    
    /**
     * 抽象的基本方法,泡制饮料
     */
    protected abstract void addCondiments();
    
    /**
     * 抽象的基本方法,加入调味料
     */
    protected abstract void brew();

}

2-2 子类实现

代码编写

1.编写Coffee类

package com.myimooc.designpattern.c8template;

/**
 * @title 模版模式
 * @describe 具体子类,提供了咖啡之中的具体实现
 * @author zc
 * @version 1.0 2017-09-02
 */
public class Coffee extends RefreshBeverage {

    @Override
    protected void addCondiments() {
        System.out.println("用沸水冲泡咖啡");
    }

    @Override
    protected void brew() {
        System.out.println("加入糖和牛奶");
    }
}

2.编写Tea类

package com.myimooc.designpattern.c8template;

/**
 * @title 模版模式
 * @describe 具体子类,提供了制备茶的具体实现
 * @author zc
 * @version 1.0 2017-09-02
 */
public class Tea extends RefreshBeverage {

    @Override
    protected void addCondiments() {
        System.out.println("用80度的热水浸泡茶叶5分钟");
    }

    @Override
    protected void brew() {
        System.out.println("加入柠檬");
    }
}

3.编写RefreshBeverageTest类

package com.myimooc.designpattern.c8template;

/**
 * @title 模版模式
 * @describe 测试类
 * @author zc
 * @version 1.0 2017-09-02
 */
public class RefreshBeverageTest {

    public static void main(String[] args) {
        
        System.out.println("制备咖啡...");
        RefreshBeverage b1 = new Coffee();
        b1.prepareBeverageTemplate();
        System.out.println("咖啡好了!");
        
        System.out.println("\n****************************************");
        
        System.out.println("制备茶...");
        RefreshBeverage b2 = new Tea();
        b2.prepareBeverageTemplate();
        System.out.println("茶好了!");
        
    }

}

2-3 钩子方法

业务场景

目前的提神饮料的步骤是固定的,当有些人不需要加入调味料时,使用钩子方法进行个性化扩展。

代码编写

1.修改RefreshBeverage类

package com.myimooc.designpattern.c8template;

/**
 * @title 模版模式
 * @describe 抽象基类,为所有子类提供一个算法框架。提神饮料
 * @author zc
 * @version 1.0 2017-09-02
 */
public abstract class RefreshBeverage {
    
    /**
     * 制备饮料的模版方法
     * 封装了所有子类共同遵循的算法框架
     */
    public final void prepareBeverageTemplate(){
        // 步骤1 将水煮沸
        boilWater();
        
        // 步骤2 泡制饮料
        brew();
        
        // 步骤3 将饮料倒入杯中
        pourInCup();
        
        if (isCustomerWantsCondiments()){
            // 步骤4 加入调味料
            addCondiments();
        }
        
    }
    
    /**
     * Hook 方法(钩子函数),提供一个默认或空的实现
     * 具体的子类可以自行决定是否挂钩以及如何挂钩
     * 询问用户是否加入调料
     */
    protected boolean isCustomerWantsCondiments() {
        // 默认需要加入调味料
        return true;
    }

    /**
     * 基本方法,将水煮沸
     */
    private void boilWater() {
        System.out.println("将水煮沸");
    }
    
    /**
     * 基本方法,将饮料倒入杯中
     */
    private void pourInCup() {
        System.out.println("将饮料倒入杯中");
        
    }
    
    /**
     * 抽象的基本方法,泡制饮料
     */
    protected abstract void addCondiments();
    
    /**
     * 抽象的基本方法,加入调味料
     */
    protected abstract void brew();

}

2.修改Tea类

package com.myimooc.designpattern.c8template;

/**
 * @title 模版模式
 * @describe 具体子类,提供了制备茶的具体实现
 * @author zc
 * @version 1.0 2017-09-02
 */
public class Tea extends RefreshBeverage {

    @Override
    protected void addCondiments() {
        System.out.println("用80度的热水浸泡茶叶5分钟");
    }

    @Override
    protected void brew() {
        System.out.println("加入柠檬");
    }
    
    /**
     * 子类通过覆盖的形式选择挂载钩子函数
     */
    @Override
    protected boolean isCustomerWantsCondiments() {
        return false;
    }
    
}

第三章:模版模式总结

3-1 总结

模版方法模式的实现要素分析

抽象基类
    1.基本方法:对各种具体子类而言是相同,具有共性的步骤
    2.抽象方法:只知道具体原则,而不知道实现细节,需要延迟到子类实现的步骤
    3.钩子方法:在基类中提供一个默认或空的实现,子类可以挂载及覆盖实现
    4.模版方法:Template方法(final),将基本方法、抽象方法、钩子方法按照业务逻辑的需求,
        汇总而成一个模版方法。一定要声明为final,以防止被子类覆写。
具体子类
    1.实现基类中的抽象方法:以提供个性化的、具体的、独特的实现
    2.覆盖钩子方法:更加个性化的影响模版方法局部的行为

模版方法模式的实现要素

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

模版方法模式的适用场景

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

模版方法模式的优点

封装性好:封装了一个算法的框架,将算法的具体步骤封装成一个通用的模版方法
复用性好:抽取共性的方式,大部分代码在父类实现,个性化逻辑由子类实现
屏蔽细节:很多共性作为私有方法在抽象基类中实现,最子类屏蔽了很多细节
便于维护:好的复用性可以减少代码框架的设计,支持更加灵活的业务变更

模版方法模式的缺点

每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

妙手空空
1.3k 声望370 粉丝

博观而约取,厚积而薄发