艺术来源于生活,有时候灵感真的就在那么一瞬间

看到上图这个板烧没有,这就是我今晚的晚餐了;走进麦当劳里面,有很多很多的汉堡

板烧鸡腿堡、麦辣鸡腿堡、麦香堡、深海鳕鱼堡…

这些个汉堡的制作方式,似乎有着一种很明显的相似感,汉堡的制作方式非常像之前学习过的一种设计模式,今天我们就来聊一聊

我们不妨更加仔细的思考一下上面的问题

  • 我要做一个【板烧鸡腿堡】

    1. 取出两块面包,烤热
    2. 放上烤热的腌制好的鸡腿肉,撒上独特的酱汁
    3. 撒上蔬菜
    4. 组合成汉堡
    5. 装在纸袋里面
  • 我要做一个【麦辣鸡腿堡】
    1. 取出两块面包,烤热
    2. 放上炸制好的鸡腿肉,撒上独特的酱汁
    3. 撒上蔬菜
    4. 组合成汉堡
    5. 装在纸袋里面
  • 我要做一个【新奥尔良烤鸡腿堡】
    1. 取出两块面包,烤热
    2. 放上新奥尔良鸡腿肉,撒上独特的酱汁
    3. 撒上蔬菜
    4. 组合成汉堡
    5. 装在纸袋里面
  • 制作其他汉堡…

有图有真相

可以发现,除了步骤2存在差异之外,其他步骤其实都是一样的,那么我们是否可以将步骤2给抽取出来,其他步骤都不变

就好像模板一般

那么我们是否可以这么做,改造一下模型图,将不变的写在超类里面,变化的由子类决定

这就是模板设计模式的思想,下面是《Head First 设计模式》对模板设计模式的解释

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

我们现在就使用模板设计模式来改造一下我们的模型图

改造后的模型图

从上图就很清晰的看到,模板设计的理念就是定义一个骨架,把公用部分挪到超类中,同时又把会变化的步骤交给子类来决定

世间众多的设计模式,都要做到一件事,那就是 封装变化点

何谓封装变化点?

  • 模板设计模式:把【个性化操作(这就是变化点)】操作延迟到未来实现,最后插入到整个定义好步骤的算法中
  • 类似的还有策略模式,同样是封装算法家族
  • 还有桥接模式,实例被定义成抽象的,通过接口交互,允许实例自由的变化而不会影响到另外的实例
  • 还有很多很多…

既然模型图出来了,那么就按照模型图来把代码敲一敲吧,天上飞的理念还是得有落地的那一刻,这是很重要的,实践出真知

/*** 定义制作汉堡包的模板流程* @author Amg* @date 2021/9/24*/
public abstract class AbstractMakeHamburgerHandler {//定义层final,确保子类不会把我“骨架”都修改了public final void execute() {baking();customize();vegetable();compose();finish();hook();}private void baking() {System.out.println("取出两块面包,烤热");}/*** 自定义步骤,可以添加你想添加的食材*/protected abstract void customize();private void compose() {System.out.println("组合汉堡");}private void vegetable() {System.out.println("撒上蔬菜");}private void packing() {System.out.println("用纸袋包裹着");}private void finish() {System.out.println("完成制作!请慢用");}protected void hook() {//这个hook方法就是一个程序“钩子”,待会会解释}
}/*** 板烧鸡腿堡* @author Amg* @date 2021/9/24*/
public class banshao extends AbstractMakeHamburgerHandler {@Overrideprotected void customize() {System.out.println("[制作板烧鸡腿堡] 专属的腌制好的鸡腿肉,撒上独特的酱汁");}}/*** 麦辣鸡腿堡** @author Amg* @date 2021/9/24*/
public class mailajituibao extends AbstractMakeHamburgerHandler {@Overrideprotected void customize() {System.out.println("[制作麦辣鸡腿堡] 放上炸制好的鸡腿肉,撒上独特的酱汁");}
}//新奥尔良就不实现了,有兴趣的朋友可以自行敲一敲(主要是肯德基你跑错地方了,这里是麦当劳专场)
public class Client {public static void main(String[] args) {AbstractMakeHamburgerHandler banshao = new banshao();banshao.execute();System.out.println("---------------------------------");mailajituibao mailajituibao = new mailajituibao();mailajituibao.execute();}}

输出结果

现在我们模型图画了,代码也敲了,那么模板设计模式有什么优缺点吗?

优点

  • 抽取共用部分到超类中,让程序更加的简洁
  • 封装不变的对象,扩展变化的部分(符合开闭原则)

缺点

  • 采用继承结构,理论上来说,每扩展一个汉堡(推出新品)就需要创建一个新的类继承超类,如果有100个汉堡,就得有100个类,这就会显示很膨胀(好处是Java 8引入了消费者接口,我们可以使用这个接口,而不必创建一大堆的新类

简单讲解一下Consumer(消费者)接口

先看看这个接口里面的方法

 /**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);/**
* Returns a composed {@code Consumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation.  If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code Consumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default Consumer<T> andThen(Consumer<? super T> after) {Objects.requireNonNull(after);return (T t) -> { accept(t); after.accept(t); };
}

我们得知道消费者这个角色的第一任务就是消费嘛,我不管什么乱七八糟的,我只知道调用accept方法,我就要去消费

至于andThen方法,返回一个组合的Consumer ,它依次执行此操作和after操作。 如果执行任一操作引发异常,则将其转发给组合操作的调用者。 如果执行此操作抛出异常,则不会执行after操作(这段是直接翻译文档过来的,解释得很透彻了)

Java8 Stream中大量使用到消费者和生产者,有兴趣的朋友也可以去了解一下(话说jdk都出到17了…)

所有,如果以Consumer方式使用模板模式,是怎么样的?直接上代码

/*** jdk1.8之后做汉堡* @author Amg* @date 2021/9/24*/
public class MakeHamburgerHandler {/*** 这个方法进行复用* @param consumer  jdk1.8之后出现的【消费者】接口,接收参数,无返回值,调用accept方法就把信息给输出出来*/private void execute(Consumer<String> consumer) {baking();consumer.accept(null);vegetable();compose();packing();finish();}private void baking() {System.out.println("取出两块面包,烤热");}private void compose() {System.out.println("组合汉堡");}private void vegetable() {System.out.println("撒上蔬菜");}private void packing() {System.out.println("用纸袋包裹着");}private void finish() {System.out.println("制作完成,客官请慢用!");}/*** 板烧鸡腿堡*/public void banshao() {execute(a -> System.out.println("[制作板烧鸡腿堡] 专属的腌制好的鸡腿肉,撒上独特的酱汁"));}/*** 麦辣鸡腿堡*/public void mailajituibao() {execute(a -> System.out.println("[制作麦辣鸡腿堡] 放上炸制好的鸡腿肉,撒上独特的酱汁"));}
}
/*** 使用JDK1.8之后提供的supplier、consumer接口,可以不再不要抽象类,以及减少类对象的创建* 而且把相同的业务给放在同一个类里面,方便后续的维护;* <p></p>* <p>但是思考一下,这样子就会违反OCP原则,上架和下架汉堡、修改汉堡佐料等等操作都需要去修改{@link MakeHamburgerHandler}</p>** @author Amg* @date 2021/9/24*/
public class Client {public static void main(String[] args) {MakeHamburgerHandler makeHamburgerHandler = new MakeHamburgerHandler();makeHamburgerHandler.banshao();System.out.println("------------------jdk1.8之后模板模式的使用------------------------");makeHamburgerHandler.mailajituibao();System.out.println("------------------jdk1.8之后模板模式的使用------------------------");}
}

代码上的注释也很清晰了,这里再总结一下,使用Consumer接口,我们可以不再需要抽象类、以及一大堆的派生子类,想要什么汉堡就包装一下execute方法即可,可以说是非常的好使

但是随之而来的问题也是,我们每次修改都会动到这个类,所以是违反了OCP原则的

最最最最后一个问题,就是上面遗留的hook方法有什么用?

上面遗留的hook方法其实是一个程序钩子他一般是空方法体或者默认实现,作用是让子类有能力对算法的不同点进行挂钩,意思就是执行或者不执行额外的逻辑

通俗点就是麦当劳在点完餐之后通常还会有一些推荐点餐,我爱吃薯条(就是你了),你可以选择要还是不要,如果我想在板烧套餐里面添加,麦辣鸡腿堡套餐里面不要,要怎么做呢?

修改我们的代码

public final void execute() {baking();customize();vegetable();compose();finish();//将hook方法更名为isReceiveChipsif (isReceiveChips()) {System.out.println("薯条添加完毕!");}
}/**
* 是否接收推荐过来的薯条,默认不要
* @return false
*/
protected boolean isReceiveChips() {return false;
}//获取用户输入
protected String getUserInput() {String answer;System.out.println("是否还需要来一份薯条呢?[y/n]");BufferedReader in = new BufferedReader(new InputStreamReader(System.in));try {answer = in.readLine();} catch (IOException e) {answer = "n";}return answer;
}//板烧子类覆盖这个方法
@Override
protected boolean isReceiveChips() {String answer = getUserInput();if (answer.equalsIgnoreCase("y"))return true;return false;
}

输出的结果

可以看到,我们在板烧套餐里面重写了isReceiveChips方法,并且返回true;而在麦辣鸡腿堡套餐里面就没有这个操作,所以麦辣鸡腿堡套餐采用默认行为

再回顾一下,钩子的存在,可以让子类有能力对算法的不同点进行挂钩

写完,收工,继续吃汉堡去!

【设计模式】汉堡中的设计模式——模板方法相关推荐

  1. jdk中的设计模式_JDK中的设计模式

    jdk中的设计模式 Zen的JCG合作伙伴Brian Du Preez 是IT领域的合作伙伴, 在收集JDK中最常见的设计模式方面做得非常出色. 模式列表的确令人印象深刻且很长,因此让我们不再ba不休 ...

  2. [Head First设计模式]餐馆中的设计模式——命令模式

    系列文章 [Head First设计模式]山西面馆中的设计模式--装饰者模式 [Head First设计模式]山西面馆中的设计模式--观察者模式 [Head First设计模式]山西面馆中的设计模式- ...

  3. java中策略设计模式_Java中的设计模式(五):策略模式

    策略设计模式是行为设计模式之一.当我们为特定任务使用多个算法时,使用策略模式,客户端决定在运行时使用的实际实现. 策略模式的最佳示例之一是Collections.sort()采用Comparator参 ...

  4. android 构建者设计模式,Android中的设计模式之构建者模式

    参考 <设计模式:可复用面向对象软件的基础 >3.2 Builder 生成器--对象创建型模式 <Android源码设计模式解析与实战>第3章 Builder模式 意图 将一个 ...

  5. 精通python设计模式-浅谈Python设计模式 - 原型模式

    声明,本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 在<精通Python设计模式>中把设计模式分为三种类型: 创建型模式 ...

  6. java 模板方法设计模式_Java中的模板方法设计模式

    java 模板方法设计模式 模板方法是一种行为设计模式 ,用于创建方法存根并将某些实现步骤推迟到子类. 模板方法定义了执行算法的步骤,它可以提供默认实现,该实现对于所有或某些子类可能是通用的. 让我们 ...

  7. Ruby中的设计模式

    继续 上 节讲述过的Singleton . Proxy 及 Iterator各模式,本节再来考察几个别的设计模式.下面按顺序来考察 Prototype . Template Method 和 Obse ...

  8. Java设计模式之行为型:模板方法模式

    一.什么是模板方法模式: 模板方法是基于继承实现的,在抽象父类中声明一个模板方法,并在模板方法中定义算法的执行步骤(即算法骨架).在模板方法模式中,可以将子类共性的部分放在父类中实现,而特性的部分延迟 ...

  9. JDK和Spring中的设计模式

    JDK中的设计模式(17) 创建型 1)工厂方法 Collection.iterator() 由具体的聚集类来确定使用哪一个Iterator 2)单例模式 Runtime.getRuntime() 3 ...

最新文章

  1. java 读取文件,内容方置Person 并写到另外地址
  2. python爬虫入门(六) Scrapy框架之原理介绍
  3. boost::mp11::mp_pop_back相关用法的测试程序
  4. python文件打开模式中、使用w模式、文件指针指向_被python文件模式“w+”所迷惑
  5. 两个序列的中位数c语言,小白在线求教 用归并排序实现查找两个有序序列的中位数...
  6. EasyUI--权限管理(二)显示左侧菜单
  7. C++ 作用域使用规范建议
  8. 动网论坛帖子跟帖展开/关闭测试
  9. Android手机使用Windows应用,微软宣布在你的手机应用上运行安卓APP功能向Windows 10稳定版提供...
  10. itop4412的安卓驱动移植
  11. Cisco 模拟器rstp生成树
  12. 潇洒郎:Ten-fold-cross validation- Naïve Bayes Classifier 十字交叉验证-贝叶斯分类器 Python实现
  13. PostgreSQL的hook机制初步学习
  14. convolution backbone network——Deep Pyramidal Residual Networks
  15. 今日恐慌与贪婪指数为24 恐慌程度有所缓解
  16. (数据结构)1.实现顺序栈的各种基本运算 2.实现环形队列的各种基本运算
  17. 搜狗输入法截屏不能用了
  18. DHU Matlab Experiment【7】考试复盘
  19. wsdl2java asmx_在WebService asmx中格式化SOAP消息
  20. 没想到你是这样的京东!论京东的品牌价值观

热门文章

  1. SOLIDWORKS 30个使用技巧
  2. 楼盘vr虚拟样板间,为售楼中心带来财气
  3. i9 10910和i7 10700哪个好
  4. 设计自学-色彩基础-手绘色彩
  5. 一网友在电脑城混了三年了,对装机的心得
  6. 事务的隔离级别和传播行为!
  7. WIN10 +小皮面板 部署CRMEB商城系统(详细步骤)
  8. 搜狗百科词条创建报价为何跨度这么大?
  9. 新版计算机软件著作权申请详细教程
  10. 杭州特色景致的性价比精致餐厅