一个最简单的设计模式-模板方法

《Head First设计模式》已经读了不止一遍,可是始终没有进行系统的进行总结。因此近期开始总结设计模式相关的知识,从模板方法模式开始,由于是一个我认为是最简单的设计模式。(推荐视频资源23个设计模式java

提出&解决问题

提出问题程序员

实现制做咖啡功能。且制做咖啡须要四个步骤 :算法

  1. 烧水
  2. 冲泡咖啡
  3. 倒入杯中
  4. 加糖

代码实现设计模式

/**
 * 一杯加糖咖啡
 *
 * @author Jann Lee
 * @date 2019-07-14 18:37
 */
public class Coffee {

    /**
     * 制做一杯加糖咖啡
     */
    public void prepareRecipe() {
        boilWater();
        steepTeaBag();
        portInCup();
        addLemon();
    }

    /**
     * step1: 烧水
     */
    private void boilWater() {
        System.out.println("烧水...");
    }

    /**
     * step2:冲泡咖啡
     */
    private void steepTeaBag() {
        System.out.println("冲泡咖啡...");
    }

    /**
     * step3: 倒入杯中
     */
    private void portInCup() {
        System.out.println("倒入杯中...");
    }

    /**
     * step4: 加糖
     */
    private void addLemon() {
        System.out.println("加糖...");
    }

再次提出问题此时此刻我须要一杯柠檬茶呢?【烧水,冲泡茶包,倒入杯中,加柠檬】cookie

这个问题固然很简单,咱们只须要如法炮制便可。框架

public class Tea {

    /**
     * 制做一杯柠檬茶
     */
    public void prepareRecipe(){
        boilWater();
        brewCoffeeGrinds();
        portInCup();
        addSugarAndMilk();
    }

    /**
     * step1: 烧水
     */
    private void boilWater() {
        System.out.println("烧水...");
    }

    /**
     * step2:冲泡咖啡
     */
    private void brewCoffeeGrinds() {
        System.out.println("冲泡茶包...");
    }

    /**
     * step3: 倒入杯中
     */
    private void portInCup() {
        System.out.println("倒入杯中...");
    }

    /**
     * step4: 加柠檬
     */
    private void addSugarAndMilk() {
        System.out.println("加入柠檬片...");
    }
}

思考ide

​ 若是此时咱们又须要一杯不加柠檬的茶,加奶的咖啡...,固然咱们能够按照上面方式从新依次实现便可。可是若是你是一个有经验的程序员,或者你学习过设计模式。你可能会发现以上功能实现的步骤/流程固定,当需求发生变化时,只有小部分步骤有所改变学习

优化代码

根据面向对象程序的特色,既抽象,封装,继承,多态。咱们能够对代码进行抽象,将公共代码提取到基类。咱们将咖啡和茶抽象成咖啡因饮料,将其中相同的两步,烧水和倒入杯中再父类中实现,将冲泡和添加调料延迟到子类。优化

  1. 定义一个基类
public abstract class CafeineBeverage {
    /**
     * 制做一杯咖啡因饮料
     */
    public void prepareRecipe() {
        boilWater();
        brew();
        portInCup();
        addCondiments();
    }

    /**
     * step1: 烧水
     */
    private void boilWater() {
        System.out.println("烧水...");
    }

    /**
     * step2:冲泡
     */
    protected abstract void brew();

    /**
     * step3: 入杯中
     */
    private void portInCup() {
        System.out.println("倒入杯中...");
    }

    /**
     * step4: 加调料
     */
    protected abstract void addCondiments();
}
// 一杯加糖咖啡
public class CoffeeBeverage extends CafeineBeverage{

    @Override
    protected void brew() {
        System.out.println("冲泡咖啡...");
    }

    @Override
    protected void addCondiments() {
        System.out.println("加糖...");
    }
}
// 一杯柠檬茶
public class TeaBeverage extends CafeineBeverage {
    @Override
    protected void brew() {
        System.out.println("冲泡茶包...");
    }

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

模板方法模式

若是按以上方式对代码进行了优化,其实就实现了模板方法模式。一下是模板方法模式相关概念。网站

动机

  • 在软件构建过程当中,对于某一项任务,它经常有稳定的总体操做结构,可是各个子步骤却有不少改变的需求,或者因为固有的缘由(好比框架与应用之间的关系)而没法和任务的总体结构同时实现
  • 如何在肯定稳定的操做结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求?

定义

定义一个操做中算法的骨架(稳定),而将一些步骤延迟(变化)到子类。Template Method使得子类能够不改变(复用)一个算法的结构,便可从新定义(override)该算法的特定步骤。

要点总结

  • Template Method是一种很是基础性的设计模式,在面向对象系统中,有着大量的应用。他用最简洁的机制(抽象类的多态,为不少应用框架提供了灵活的扩展点,是代码复用方面最基本实现结构)
  • 除了能够灵活应对子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是Template Method的典型应用
  • 在具体实现方面,被Template Method调用得虚方法能够有实现,也能够没有实现(抽象方法),但通常推荐设置为protected方法

类图:

我的博客网站(正在建设中)

相关文章
相关标签/搜索