十、模板方法模式—制作更多好喝的饮品! #和设计模式一起旅行#

无规矩不成方圆!故事背景在安装了酷炫了碉堡了的灯之后,我饿设计模式MM经营的奶茶店生意更加火爆,有不同国家的顾客,那么为了满足更多消费者的口味,我们推出了中国龙井苹果茶和叶门摩卡牛奶咖啡。其中制作的过程:把水烧开将咖啡/茶叶放到杯子里用沸水冲泡加入牛奶/苹果汁下面用代码来表示茶和咖啡的制作过程!//龙井苹果茶制作public class LongJi…

大家好,又见面了,我是全栈君。

无规矩不成方圆!

故事背景

在安装了酷炫了碉堡了的灯之后,我和设计模式MM经营的奶茶店生意更加火爆,有不同国家的顾客,那么为了满足更多消费者的口味,我们推出了中国龙井苹果茶和叶门摩卡牛奶咖啡。其中制作的过程:

  • 把水烧开
  • 将咖啡/茶叶放到杯子里
  • 用沸水冲泡
  • 加入牛奶/苹果汁

下面用代码来表示茶和咖啡的制作过程!

//龙井苹果茶制作
public class LongJinTea { 
   

    /** * 制作方法 */
    public void makeMethod(){
        boliWater();
        putMaterialToCup();
        pourInCup();
        addAppleJuice();
    }

    /** * 烧水 */
    private void boliWater() {
        System.out.println("---将水煮沸-----");
    }

    /** * 将原料放入杯子 */
    private void putMaterialToCup() {
        System.out.println("---将龙井茶叶放入杯子中-----");
    }

    /** * 用沸水冲泡 */
    private void pourInCup() {
        System.out.println("---将沸水倒入杯子-----");
    }

    /** * 加入苹果汁 */
    private void addAppleJuice() {
        System.out.println("---在浸泡龙井茶叶的杯子中加入苹果汁-----");
    }

}


//摩卡牛奶咖啡
public class MOKACoffee { 
   

    /** * 制作方法 */
    public void makeMethod(){
        boliWater();
        putMaterialToCup();
        pourInCup();
        addMilk();
    }

    /** * 烧水 */
    private void boliWater() {
        System.out.println("---将水煮沸-----");
    }

    /** * 将原料放入杯子 */
    private void putMaterialToCup() {
        System.out.println("---将咖啡放入杯子中-----");
    }

    /** * 用沸水冲泡 */
    private void pourInCup() {
        System.out.println("---将沸水倒入杯子-----");
    }

    /** * 加入牛奶 */
    private void addMilk() {
        System.out.println("---在浸泡咖啡的杯子中加入牛奶-----");
    }
}


设计模式MM:
1. 上面的代码我发现很多重复的代码啊!这个咖啡和茶的制作过程如此相似,应该考虑抽取共同部分,放入一个基类中。
2. 上面的整个制作流程其实可以看做是一个算法的步骤,这几个步骤的次序是:①烧水 –> ②往杯子放原料 –> ③加入沸水—> ④加入其它添加物,其中只有②和④不同。

建议你去看看模板方法模式!

我: 好的!

故事主角-模板方法模式

模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构的情况下,重新定义的算法中某些步骤。

模板方法模式是一种基础继承的代码复用技术。

模板方法模式类图

模板方法模式包含两个角色:

  • AbstractClass(抽象类):这个抽象类包含了一个模板方法,在这个模板方法的一系列方法可以是具体的,也可以是抽象的,每个基本的操作对应算法的一个步骤,其中抽象的步骤由子类定义实现。
  • ConcreteClass(具体子类):抽象类的子类,用于实现父类模板方法中算法的步骤,也可以覆盖父类中已经实现的基本操作。

模板方法模式的实现

模板中定义了一个算法的框架,其中包括:

  • 1.模板方法

    把基本操作方法组合在一起形成一个总算法或一个总行为的方法!这个模板方法定义在抽象类中,由子类不加以修改的完全继承!

  • 2.基本方法

    基本方法实现算法各个步骤的方法,是模板方法的组成部分。基本方法有可以分为三种:
    (1) 抽象方法(AbstractMethod)
    (2) 具体方法(ConcreteMethod)
    (3) 钩子方法(HookMethod)

(1)抽象方法(AbstractMethod):抽象类申明一个抽象方法,由其子类去实现。
(2)具体方法(ConcreteMethod):抽象类申明并实现一个具体方法,也可以由子类进行覆盖。
(3)钩子方法(HookMethod):抽象类申明并实现一个钩子方法,抽象类一般可以订阅为空实现。可以由其子类加以扩展。

在模板方法模式中,程序在运行时,具体子类的基本方法可以覆盖父类中定义的基本方法,子类的钩子方法也可以覆盖父类的钩子方法,从而可以通过在子类中实现的钩子方法对父类方法的执行进行约束,实现子类对父类行为的反向控制。【现在在武功修改中讲解这一话的意思】

武功修炼

public abstract class GreatBeverage { 
   

    /** * 制作最棒饮品的模板方法 */
    public final void makeBeverage(){
        boliWater();
        putMaterialToCup();
        pourInCup();
        addCondiments();
    }

    /** * 烧水 */
    public void boliWater() {
        System.out.println("---将水煮沸-----");
    }

    /** * 将原料放入杯子 */
    public abstract void putMaterialToCup() ;

    /** * 用沸水冲泡 */
    public void pourInCup() {
        System.out.println("---将沸水倒入杯子-----");
    }

    /** * 加入饮品的调味品 */
    public abstract void addCondiments();
}

//龙井苹果茶制作
public class LongJinTea extends GreatBeverage { 
   

    /** * 将原料放入杯子 */
    @Override
    public void putMaterialToCup() {
        System.out.println("---将龙井茶叶放入杯子中-----");
    }


    /** * 加入苹果汁 */
    @Override
    public void addCondiments() {
        System.out.println("---在浸泡龙井茶叶的杯子中加入苹果汁-----");
    }

}

//摩卡牛奶咖啡
public class MOKACoffee extends GreatBeverage{ 
   

    /** * 将原料放入杯子 */
    @Override
    public void putMaterialToCup() {
        System.out.println("---将咖啡放入杯子中-----");
    }

    /** * 加入牛奶 */
    @Override
    public void addCondiments() {
        System.out.println("---在浸泡咖啡的杯子中加入牛奶-----");
    }
}

public class Test { 
   

    public static void main(String[] args) {
        //来了个叶门顾客
        GreatBeverage gb = new LongJinTea();
        gb.makeBeverage();//制作龙井苹果茶

        System.out.println("==============华丽的分割线===========");

        //来了一个中国顾客
        gb = new MOKACoffee();//制作摩卡牛奶咖啡
        gb.makeBeverage();

    }
}


---将水煮沸-----
---将龙井茶叶放入杯子中-----
---将沸水倒入杯子-----
---在浸泡龙井茶叶的杯子中加入苹果汁-----
==============华丽的分割线===========
---将水煮沸-----
---将咖啡放入杯子中-----
---将沸水倒入杯子-----
---在浸泡咖啡的杯子中加入牛奶-----

目前我们买的龙井苹果茶或者摩卡牛奶咖啡都是假如了调味料,为了人性化,提示顾客的品味体验,我们会在制作的时候咨询顾客是否需要假如调味料,那么我们改怎么实现呢?【这里就使用到上面的钩子方法】,在泡茶的水使用高端设备进行烧水。

具体的代码如下:

public abstract class GreatBeverage { 
   

    /** * 制作最棒饮品的模板方法 */
    public final  void makeBeverage(){
        boliWater();
        putMaterialToCup();
        pourInCup();
        if(isAddCondiment()){
  
  //加上判断,可以由具体方法进行判断决定
            addCondiments();
        }

    }

    /** * 烧水 */
    public void boliWater() {
        System.out.println("---将水煮沸-----");
    }

    /** * 将原料放入杯子 */
    public abstract void putMaterialToCup() ;

    /** * 用沸水冲泡 */
    public void pourInCup() {
        System.out.println("---将沸水倒入杯子-----");
    }

    /** * 加入饮品的调味品 */
    public abstract void addCondiments();

    /** * 钩子方法,默认实现 * @return */
    public boolean isAddCondiment(){
        return true;
    }
}
//龙井苹果茶制作
public class LongJinTea extends GreatBeverage { 
   


    /** * 以覆盖父类中定义的基本方法 */
    @Override
    public void boliWater(){
        System.out.println("----泡茶使用高端的热水设备进行烧水---");
    }
    /** * 将原料放入杯子 */
    @Override
    public void putMaterialToCup() {
        System.out.println("---将龙井茶叶放入杯子中-----");
    }


    /** * 加入苹果汁 */
    @Override
    public void addCondiments() {
        System.out.println("---在浸泡龙井茶叶的杯子中加入苹果汁-----");
    }

    @Override
    public boolean isAddCondiment(){
        String answer = getUserAnswer();

        if("加".equals(answer)){
           return true;
        }else if("不加".equals(answer)){
            return false;
        }else{
  
  //随便
            return true;
        }
    }

    private String getUserAnswer() {
        System.out.println("你好,你要在龙井茶中加入苹果汁吗?");

        BufferedReader in = null;
        String answer = null;
        try {
            in = new BufferedReader(new InputStreamReader(System.in));

            answer =  in.readLine();

        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return answer;

    }

}

public class Test { 
   

    public static void main(String[] args) {
        //来了个叶门顾客
        GreatBeverage gb = new LongJinTea();
        gb.makeBeverage();//制作龙井苹果茶


    }
}


----泡茶使用高端的热水设备进行烧水---
---将龙井茶叶放入杯子中-----
---将沸水倒入杯子-----
你好,你要在龙井茶中加入苹果汁吗?
不加

Process finished with exit code 0


----泡茶使用高端的热水设备进行烧水---
---将龙井茶叶放入杯子中-----
---将沸水倒入杯子-----
你好,你要在龙井茶中加入苹果汁吗?
加
---在浸泡龙井茶叶的杯子中加入苹果汁-----

Process finished with exit code 0

上面的这一段代码实例就解释 了,在模板方法模式中,程序在运行时,具体子类的基本方法可以覆盖父类中定义的基本方法,子类的钩子方法也可以覆盖父类的钩子方法,从而可以通过在子类中实现的钩子方法对父类方法的执行进行约束,实现子类对父类行为的反向控制。

注意:为了防止子类去修改模板方法中的算法结构,可以将模板方法设置为final。

武功深入 – 模板方法模式和策略模式比较

模板方法模式:
– 定义一个算的大纲,由子类去实现算法大纲中某些步骤内容,虽然算法中个别步骤可以由不同的实现,但整体的算法结构维持不变。
– 使用继承方式,对算法有更多的控制权,实现代码复用
– 使用较多的模式

策略模式:
– 定义一个算法家族,并让算法之间可以互换
– 使用对象对象组合,更有弹性

武功应用场景思考

  1. 根据模板方法模式设计一个电商系统付款场景,比如付款可以是微信、支付宝、银联!

    思路提示 – 付款简单包含:参数检验 、 调用支付请求、返回结果处理、回调的操作等

  2. JDK、Tomcat、Spring等中哪些地方使用到了模板方法模式?

    思路提示: JDK的ClassLoader;JDK中CompareTo的实现(符合模板方法的精神);Tomcat中关于生命周期管理的地方很好应用了模板方法模式;Spring中的JdbcTemplate。

Next 期待下一篇吧!制作更多好喝的饮品!我的这个旅行创业成功后,很多媒体活动需要参加,那么我要对接很多活动和处理很多问题。于是我想请一个助理,代理我做一些接活动和处理问题的事情,我只负责参加活动即可!下一篇:代理模式,解放自己,让我能更加专注核心业务处理。

参考

本专栏文章列表

一、设计模式-开篇—为什么我要去旅行? #和设计模式一起旅行#
二、设计模式-必要的基础知识—旅行前的准备 #和设计模式一起旅行#
三、设计模式介绍—她是谁,我们要去哪里? #和设计模式一起旅行#
四、单例模式—不要冒充我,我只有一个! #和设计模式一起旅行#
五、工厂模式—旅行的钱怎么来 #和设计模式一起旅行#
六、策略模式—旅行的交通工具 #和设计模式一起旅行#
七、观察者模式——关注我,分享旅途最浪漫的瞬间! #和设计模式一起旅行#
八、装饰者模式—巴厘岛,奶茶店的困扰! #和设计模式一起旅行#
九、命令模式—使用命令控制奶茶店中酷炫的灯 #和设计模式一起旅行#
十、模板方法模式—制作更多好喝的饮品! #和设计模式一起旅行#
十一、代理模式 —专注,做最好的自己!#和设计模式一起旅行#
十二、适配器模式——解决充电的烦恼 #和设计模式一起旅行#
十三、外观模式—— 简化接口 #和设计模式一起旅行#
十四、迭代器模式—— 一个一个的遍历 #和设计模式一起旅行#
十五、组合模式—— 容器与内容的一致性 #和设计模式一起旅行#
十六、状态模式—用类表示状态 #和设计模式一起旅行#
十七、访问者模式-访问数据结构并处理数据 #和设计模式一起旅行#
十八、职责链模式-推卸责任,不关我的事,我不管!#和设计模式一起旅行#
十九、原型模式—通过复制生产实例 #和设计模式一起旅行#
二十、设计模式总结—后会有期 #和设计模式一起旅行#


如果您觉得这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到,谢谢!

如果帅气(美丽)、睿智(聪颖),和我一样简单善良的你看到本篇博文中存在问题,请指出,我虚心接受你让我成长的批评,谢谢阅读!
祝你今天开心愉快!


欢迎访问我的csdn博客,我们一同成长!

不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

博客首页 : http://blog.csdn.net/u010648555

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/121093.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号