前言介绍


接下里介绍的是Java 的设计模式之一:模板模式

咱们还是以一个问题进行开展,引入模板模式

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

制作豆浆的流程为:选材--->增加配料--->浸泡--->放到豆浆机打碎

要求:通过增加不同的配料,能够制作出不同口味的豆浆

比如说:增加黑芝麻配料就是黑芝麻豆浆、红豆配料就是红豆豆浆

那么选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的

这样的流程步骤差不多是一样的,咱们举荐应用:模板模式

一、什么是模板模式


模板办法模式(Template Method Pattern),又叫模板模式(Template Pattern)

一个抽象类公开定义了执行它的办法的模板

它的子类能够按须要重写办法实现,但调用将以抽象类中定义的形式进行

简略说,模板办法模式 定义一个操作中的算法的骨架,而将一些步骤提早到子类中

使得子类能够不扭转一个算法的构造,就能够重定义该算法的某些特定步骤

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

模板模式原理类图剖析

AbstractClass 抽象类

定义了大抵的算法骨架,具体子类须要去实现 其它的形象办法 operationr2,3,4

ConcreteClass 子类

实现形象办法 operationr2,3,4, 以实现算法中特点子类的步骤

二、应用模板模式解决问题


制作豆浆的流程:选材--->增加配料--->浸泡--->放到豆浆机打碎

要求:通过增加不同的配料,能够制作出不同口味的豆浆

咱们这里举例说明:红豆豆浆、花生豆浆等等

咱们依照思路创立抽象类,定义具体流程的骨架

//抽象类,示意豆浆abstract class SoyaMilk {    //模板办法, make , 模板办法能够做成 final , 不让子类去笼罩.    final void make() {        select();        addCondiments();        soak();        beat();    }    //选资料    void select() {        System.out.println("第一步:抉择好的陈腐黄豆    ");    }    //增加不同的配料, 形象办法,  子类具体实现    abstract void addCondiments();    //浸泡    void soak() {        System.out.println("第三步, 黄豆和配料开始浸泡, 须要 3 小时 ");    }        //打碎    void beat() {        System.out.println("第四步:黄豆和配料放到豆浆机去打碎    ");    }}

若这时咱们增加配料:红豆、那么咱们就要继承这个抽象类并重写

class RedBeanSoyaMilk extends SoyaMilk {    @Override    void addCondiments() {        System.out.println(" 退出上好的红豆 ");    }}

若这时咱们增加配料:花生、那么咱们就要继承这个抽象类并重写

class PeanutSoyaMilk extends SoyaMilk {    @Override    void addCondiments() {        System.out.println(" 退出上好的花生 ");    }}

这时咱们应用demo看看依据要求创立不同的豆浆,是怎么回事呢?

public static void main(String[] args) {    //制作红豆豆浆    System.out.println("----制作红豆豆浆----");    SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();    redBeanSoyaMilk.make();    //制作黄豆豆浆    System.out.println("---- 制 作 花 生 豆 浆 ----");    SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();    peanutSoyaMilk.make();}运行后果如下:----制作红豆豆浆----第一步:抉择好的陈腐黄豆    退出上好的红豆 第三步, 黄豆和配料开始浸泡, 须要 3 小时 第四步:黄豆和配料放到豆浆机去打碎    ---- 制 作 花 生 豆 浆 ----第一步:抉择好的陈腐黄豆    退出上好的花生 第三步, 黄豆和配料开始浸泡, 须要 3 小时 第四步:黄豆和配料放到豆浆机去打碎

三、模板模式的钩子办法

那么什么是钩子办法呢?

在模板办法模式的父类中,咱们能够定义一个办法,它默认不做任何事,子类能够视状况要不要笼罩它,该办法称为“钩子”

咱们以豆浆的利用示例来解说阐明看看

比方咱们还心愿制作纯豆浆,但不增加任何的配料,请应用钩子办法对后面的模板办法进行革新

//抽象类,示意豆浆abstract class SoyaMilk {    //模板办法, make , 模板办法能够做成 final , 不让子类去笼罩.    final void make() {        select();        //依据钩子办法来决定是否须要增加配料        if(customerWantCondiments()) {            addCondiments();        }        soak();        beat();    }    //钩子办法,决定是否须要增加配料    boolean customerWantCondiments() {        return true;    }    //选资料    void select() {        System.out.println("第一步:抉择好的陈腐黄豆    ");    }    //增加不同的配料, 形象办法,  子类具体实现    abstract void addCondiments();    //浸泡    void soak() {        System.out.println("第三步, 黄豆和配料开始浸泡, 须要 3 小时 ");    }    //打碎    void beat() {        System.out.println("第四步:黄豆和配料放到豆浆机去打碎    ");    }}

这时咱们依据要求增加一个原豆浆类重写他,然而他不增加配料

class PureSoyaMilk extends SoyaMilk {    //若不须要增加配料 则空办法重写    @Override    void addCondiments() {}    //若不须要增加配料则将钩子至为false    @Override    boolean customerWantCondiments(){return false;}}

这时咱们应用demo看看依据要求创立纯豆浆,是怎么回事呢?

public static void main(String[] args) {    //制作红豆豆浆    System.out.println("----制作红豆豆浆----");    SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();    redBeanSoyaMilk.make();    //制作纯豆浆    System.out.println("---- 制 作 纯 豆 浆 ----");    SoyaMilk pureSoyaMilk = new PureSoyaMilk();    pureSoyaMilk.make();}运行后果如下:---- 制 作 花 生 豆 浆 ----第一步:抉择好的陈腐黄豆    退出上好的花生 第三步, 黄豆和配料开始浸泡, 须要 3 小时 第四步:黄豆和配料放到豆浆机去打碎    ---- 制 作 纯 豆 浆 ----第一步:抉择好的陈腐黄豆    第三步, 黄豆和配料开始浸泡, 须要 3 小时 第四步:黄豆和配料放到豆浆机去打碎

四、模板办法模式的注意事项和细节

根本思维是:算法只存在于一个中央,也就是在父类中,容易批改

须要批改算法时,只有批改父类的模板办法或者曾经实现的某些步骤,子类就会继承这些批改

实现了最大化代码复用。

父类的模板办法和已实现的某些步骤会被子类继承而间接应用

既对立了算法,也提供了很大的灵活性。

父类的模板办法确保了算法的构造放弃不变,同时由子类提供局部步骤的实现

该模式的不足之处:每一个不同的实现都须要一个子类实现,导致类的个数减少,使得零碎更加宏大

个别模板办法都加上 final 关键字, 避免子类重写模板办法.

模板办法模式应用场景:当要实现在某个过程,该过程要执行一系列步骤 ,这一系列的步骤基本相同,但其个别步骤在实现时可能不同,通常思考用模板办法模式来解决

参考资料


尚硅谷:设计模式(韩顺平老师):模板模式

Refactoring.Guru:《深刻设计模式》