zoukankan      html  css  js  c++  java
  • 设计模式之模板方法模式

    基本概念

    模板方法模式,又叫模板模式。在一个抽象类中公开定义了执行它的方法的模板,它的子类可以按需重写方法实现,但调用将以抽象类中定义的方式进行。

    简单说,模板模式定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤。

    这种类型的设计模式属于行为型模式。

    模板方法模式的原理类图

    • AbstractClass,抽象类,类中实现了模板方法,定义了算法的骨架,具体子类需要去实现。其他的抽象方法有operation2,3,4。
    • ConcreteClass,实现抽象方法operation2,3,4,以完成算法中特定子类的步骤。

    模板方法模式

    案例

    编写制作豆浆的程序,说明如下:

    • 制作豆浆的流程:选材—>添加配料—>浸泡—>放到豆浆机打碎。
    • 通过添加不同的配料,可以制作出不同口味的豆浆。
    • 选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的。
    • 请使用模板方法模式完成。

    思路分析

    代码实现

     1//抽象类,表示豆浆
    2public abstract class SoyaMilk {
    3
    4    //模板方法,使用final修饰,不让子类去覆盖
    5    final void make(){
    6        select();
    7        addCondiments();
    8        soak();
    9        beat();
    10    }
    11
    12    //选材料
    13    void select (){
    14        System.out.println("第一步,选择好的新鲜黄豆");
    15    }
    16
    17    //添加不同的配料
    18    abstract void addCondiments();
    19
    20    //浸泡
    21    void soak(){
    22        System.out.println("第三步,黄豆和配料开始浸泡");
    23    }
    24
    25    void beat(){
    26        System.out.println("第四步,黄豆和配料放到豆浆机打碎");
    27    }
    28
    29}

    1public class RedBeanSoyaMilk  extends SoyaMilk{
    2    @Override
    3    void addCondiments() {
    4        System.out.println("加入上好的红豆");
    5    }
    6}

    1public class PeanutSoyMilk extends SoyaMilk {
    2    @Override
    3    void addCondiments() {
    4        System.out.println("加入上好的花生");
    5    }
    6}

     1public class Client {
    2    public static void main(String[] args) {
    3        //制作红豆豆浆
    4        SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();
    5        redBeanSoyaMilk.make();
    6        //制作花生豆浆
    7        SoyaMilk peanutSoyMilk = new PeanutSoyMilk();
    8        peanutSoyMilk.make();
    9    }
    10}

    模板方法模式的钩子方法

    在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”。

     1//抽象类,表示豆浆
    2public abstract class SoyaMilk {
    3
    4    //模板方法,使用final修饰,不让子类去覆盖
    5    final void make(){
    6        select();
    7        if (customerWantCondiments()){
    8            addCondiments();
    9        }
    10        soak();
    11        beat();
    12    }
    13
    14    //选材料
    15    void select (){
    16        System.out.println("第一步,选择好的新鲜黄豆");
    17    }
    18
    19    //添加不同的配料
    20    abstract void addCondiments();
    21
    22    //浸泡
    23    void soak(){
    24        System.out.println("第三步,黄豆和配料开始浸泡");
    25    }
    26
    27    void beat(){
    28        System.out.println("第四步,黄豆和配料放到豆浆机打碎");
    29    }
    30
    31    //钩子方法,决定是否需要添加配料
    32    boolean customerWantCondiments(){
    33        return true;
    34    }
    35}

     1public class PureSoyaMilk extends SoyaMilk {
    2    @Override
    3    void addCondiments() {
    4       //空实现
    5    }
    6
    7    @Override
    8    boolean customerWantCondiments() {
    9        return false;
    10    }
    11}

    注意事项

    基本思想是:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改。
    实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用。

    既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现。

    该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大。

    一般模板方法都加上final关键字,防止子类重写模板方法。

    模板方法模式使用场景:当要完成在某个过程,该过程要执行一系列步骤,这一系列的步骤基本相同,但其个别步骤在实现时可能不同,通常考虑用模板方法模式来处理。

  • 相关阅读:
    欧拉函数 & 【POJ】2478 Farey Sequence & 【HDU】2824 The Euler function
    【BZOJ】2982: combination(lucas定理+乘法逆元)
    【vijos】1781 同余方程(拓展欧几里得)
    Disillusioning #1 水题+原题赛(被虐瞎)
    【HDU】3622 Bomb Game(2-SAT)
    小结:双连通分量 & 强连通分量 & 割点 & 割边
    【POJ】2942 Knights of the Round Table(双连通分量)
    【POJ】1523 SPF(割点)
    【POJ】1094 Sorting It All Out(拓扑排序)
    小结:网络流
  • 原文地址:https://www.cnblogs.com/fairboyllil/p/13455107.html
Copyright © 2011-2022 走看看