• 模板方法模式学习笔记


    模板方法的实现要素:抽象基类和具体子类

    抽象基类:(1)基本方法:共有的方法,用private修饰

         (2)抽象方法:只知道原则,不知道具体实现,要延迟到子类中实现,用protected abstract修饰

           (3)可选的钩子:具体的子类可以自行决定是否挂钩以及如何挂钩,从而影响算法的实现,用protected修饰

           (4)Template方法:封装了所有子类共同遵循的算法框架,用final修饰,不让子类覆盖重写。

                     模板方法定义成final,即表示子类可以替换掉父类中的可变逻辑,但不能改变掉整体逻辑结构。(好莱坞原则)

    具体子类:(1)实现基类中的抽象方法

           (2)可选的覆盖钩子方法,来更加个性化来影响算法的局部行为。

    总结:

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

    模板方法模式的适用场景:

    (1)算法或操作遵循相似的逻辑

    (2)重构时(把相同的代码抽取到父类中)

    (3)重要,复杂的算法,核心算法设计为模板算法

    模板方法模式的优点:

    (1)封装性好

    (2)复用性好

    (3)屏蔽细节

    (4)便于维护

    模板方法模式的缺点:

    (1)继承(Java语言只支持单继承),但我们重构一个系统时,假如有些类已经继承了相关父类,那就无法再继承模板方法的抽象基类。

    简单代码示例如下:

    /**
    * 抽象基类,为所有子类提供一个算法框架
    *
    * 提神饮料
    *
    * @author zhx
    *
    */
    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("将水煮沸");
    }

    /*
    * 抽象的基本方法,泡制饮料
    */
    protected abstract void brew();

    /*
    * 基本方法,将饮料倒入杯中
    */
    private void pourInCup() {
    System.out.println("将饮料倒入杯中");
    }

    /*
    * 抽象的基本方法:加入调味料
    */
    protected abstract void addCondiments();

    }

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

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

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

    }

    /**
    * 具体子类:提供了制备茶的具体实现
    * @author zhx
    *
    */
    public class Tea extends RefreshBeverage{

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

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

    /*
    * 子类通过覆盖的形式选择挂载钩子函数
    * @see edu.bnuz.zhx.design_pattern.template.RefreshBeverage#isCustomerWantsCondiments()
    */
    @Override
    protected boolean isCustomerWantsCondiments() {
    return false;
    }

    }

    public class RefreshBeverageTest {

    public static void main(String[] args) {

    System.out.println("制备咖啡中...");
    RefreshBeverage coffee = new Coffee();
    coffee.prepareBeverageTemplate();
    System.out.println("咖啡制备完成...");

    System.out.println("-----------------------------------");
    System.out.println("制备茶中...");
    RefreshBeverage tea = new Tea();
    tea.prepareBeverageTemplate();
    System.out.println("茶制备完成...");
    }

    }

  • 相关阅读:
    HDU1875——畅通工程再续(最小生成树:Kruskal算法)
    CodeForces114E——Double Happiness(素数二次筛选)
    POJ3083——Children of the Candy Corn(DFS+BFS)
    POJ3687——Labeling Balls(反向建图+拓扑排序)
    SDUT2157——Greatest Number(STL二分查找)
    UVA548——Tree(中后序建树+DFS)
    HDU1312——Red and Black(DFS)
    生活碎碎念
    SQL基础四(例子)
    Linux系统中的一些重要的目录
  • 原文地址:https://www.cnblogs.com/houxi/p/4565268.html
Copyright © 2020-2023  润新知