今天是五.四青年节,祝大家节日快乐。看着今天这标题就有食欲,夏天到了,醋溜土豆丝和清炒苦瓜适合夏天吃,好吃不上火。这两道菜大部分人都应该吃过,特别是醋溜土豆丝,作为“鲁菜”的代表作之一更是为大众所熟知,醋溜土豆丝,好吃不上火。清炒苦瓜这道菜好啊,更是夏天必备之良菜,其功效在此就不做过多赘述了。言归正传,上篇博客我们从“小弟”中学习了“外观模式”,我们也把“外观模式”戏称为“小弟模式”。今天我们要从醋溜土豆丝和清炒苦瓜的制作过程中来学习一下我们今天博客的主题“模板方法模式”(Template Method Pattern)。

说到模板方法模式,如果你看过之前发表的重构相关的博客的话,应该对模板方法模式并不陌生。在《代码重构(五):继承关系重构规则》这篇博客中第三部分,其实是使用的“模板方法模式”进行重构的,在重构规则里边我们称之为“Form Template Method (构造模板函数)”,这个模板函数就是我们本篇博客中的模板方法。今天我们要从另一个角度来看一下“模板方法模式”,并从“醋溜土豆丝”和“清炒苦瓜”的制作实例中来学习一下“模板方法模式”。在本篇博客中,你不仅是一位Programer,还是一位Cook。

老规矩,在博客的开头,我们先给出“模板方法模式”的定义。如果你是小白,定义看不懂没关系,因为定义一般都比较难理解。你可以看完下方的具体实例后在回头看这个定义即可。模板方法的定义如下:

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

一、开始炒菜

接下来我们将要开始制作我们的醋溜土豆丝和清炒苦瓜这两道菜,当然在本篇博客的第一部分我们不会使用我们的模板方法来炒菜的。我们在该部分先给出常规的做菜的方法,然后我们会对其分析,最终会使用我们的“模板方法模式”来进行炒菜。当然在此我们不是真的用锅炒菜了,而是用我们的代码来炒菜,走起。

1.炒一个醋溜土豆丝

接下来我们要炒一个醋溜土豆丝,醋溜土豆丝好吃,做起来又简单。还是那句话,醋溜土豆丝,好吃不上火。因为炒“醋溜土豆丝”我们是在一个类中完成的,所以在此就不画类图了,等下发使用模板方法模式后,在给出相应的类图。下方的FryShreddedPotatoes类就是我们做“醋溜土豆丝”的类。其中给出了做醋溜土豆丝的一系列的步骤,并且在fryShreddedPotatoes()函数中对这一系列的函数进行了组合。

上面完成的这个类,我们就可以将上述这个类进行实例化并调用fryShreddedPotatoes()来炒一盘醋溜土豆丝了。下方我们就将FryShreddedPotatoes进行实例化,然后炒了一盘醋溜土豆丝。

2、来一盘“清炒苦瓜”

上面土豆丝炒完了,已出锅。接下来我们还要来一盘“清炒苦瓜”,当然“清炒苦瓜”的做法和上面“醋溜土豆丝”差不过,不过有些步骤还是不同的。当然你在炒苦瓜的时候不能放醋了,还有在炒苦瓜的时候你放的是苦瓜片而不是土豆丝了,这些都是不同的。当然两者的菜名也不一样呢。下方这个类就是我们“清炒苦瓜”的类,你可以将该类进行实例化然后去做一盘属于你的清炒苦瓜。大体上一看,下方的代码与上面我们醋溜土豆丝的类的步骤差不多,但是具体细节,以及一些步骤所调用的方法所不同。下方就是我们清炒苦瓜的类,如下所示:

接着就是来实例化上面“清炒苦瓜”的类,然后来一盘清炒苦瓜。下方是我们创建的上面的类的对象,然后去调用炒苦瓜的方法。下方是调用方式和输出结果,经过下方的过程,我们就可以出锅一盘清炒苦瓜了,如下所示:

二、使用“模板方法”来炒菜

在上面两种炒菜的方法中,我们不难看出炒醋溜土豆丝和清炒苦瓜中的类中有好多重复的代码。在我们重构系列中的博客中我们已经提到切记重复代码,所以我们要对上面的两个类进行代码的重构,而重构的方式就是使用“模板方法模式”来进行重构。本质上就是将变的部分与不变的部分进行分离,在该实例中变的部分就是某些步骤的具体细节,而不变的是执行的步骤和部分步骤中的内容。

在该炒菜实例中整个炒菜的流程是不变的,该流程中的一些步骤也是不变的。变化的就是报菜名方法中所报的菜名不同,然后是所炒的菜不同,一个炒的是土豆丝一个炒的是苦瓜,最后是加的调料不同。这样一分析,我们可以将不变的方法放到父类中,将炒菜这个不变的步骤封装成“模板方法”,具体不变的某些步骤(比如放油等)可以放在延展中实现。该部分的代码结构些微的有些复杂,所以我们会给出相应的类图。

1.重构后的类图如下(使用了“模板方法模式”)

首先我们会给出重构后的类图,使用“模板方法模式”重构后的类图如下所示。 FryVegetablesType是我们创建的炒菜协议,其中定义了“醋溜土豆丝”和“清炒苦瓜”所有的方法,不过我们对两者不同的方法进行了重新命名,让其统一。因为两者不同的方法所实现的东西大体一致,比如之前清炒苦瓜中的放苦瓜的方法putBitterGourd(),我们重命名成了“放蔬菜”的putVegetables()方法。putVegetables()方法用于“醋溜土豆丝”中也是可以的,因为putVegetables()在“清炒苦瓜”中放的是苦瓜,在炒土豆丝中放的是土豆丝。

在FryVegetablesType协议的延展中,我们给出了相同的默认实现,比如模板方法(fry())、放油(putSomeOil())、放葱花(putSomeGreenOnion())、出锅(outOfThePan())等方法。在炒这两个菜时延展中的方法是不变的。而我们炒土豆丝和炒苦瓜中实现的方法是两者不同的地方,类图如下:

2.炒菜接口与接口延展代码实现

根据上述的类图,我们可以给出炒菜接口以及接口延展的代码实现。接下来要做的事情就是将不变的部分提取到接口和接口的延展中,下方就是我们提取的炒菜的接口FryVegetablesType以及该接口对应的延展。FryVegetablesType协议中给出了模板方法fry(),以及炒菜的步骤(也就是炒菜的算法)。在该接口的延展中,模板方法fry()的默认实现调用和这些步骤,并且给出了一些不变的步骤的实现。具体代码如下所示:

3.“醋溜土豆丝”和“清炒苦瓜”的具体实现

下方代码段是醋溜土豆丝和清炒苦瓜在模板方法模式中的代码实现。从下方代码我们不难看出,两者都遵循了FryVegetablesType协议,并且拥有该协议的默认扩展。我们知道默认扩展中的代码类似于抽象类的默认实现,为子类所共有,所以下方两个类只给出了不同的步骤。比如在醋溜土豆丝中放的作料是盐和醋,而在清炒苦瓜中放的作料是盐。当然两个子类中其他实现的两个方法也是不同之处。无论子类怎么给出默认实现的步骤,我们在默认延展中给出的模板方法是不变的,也就是炒菜的具体步骤是不变的。这就是模板方法模式,模板方法不关心每个步骤的具体细节,只关心步骤执行的顺序,这就是所谓的模板方法是对算法的封装,而不是对具体计算细节的封装。

使用模板方法的一个显而易见的好处就是减少了代码冗余,将变化的部分与不变的部分进行了分离。在该示例中就是将不变的部分放在了协议的默认延展中,将变化的部分放在了子类中。这就是“模板方法模式”。

4、“模板方法模式”的测试用例

接下来我们要对上述的示例进行测试,下方就是我们模板方法的测试用例,其实下方的测试用例与之前没有使用模板方法时的测试用例类似,只是炒菜调用的方法有所不同。虽然调用的方法有些差异,此处的差异仅仅是函数名称的差异,该函数所做的事情没有变化。下方就是我们重构后的代码的测试用例以及运行结果。从结果中看出,与我们之前没有使用模板方法的测试用例的输出结果一致。这就是我们之前在“重构”系列博客中经常提到的改变代码内部的结构,而不改变代码对外调用的接口。

本篇博客与之前我们类重构中的“构建模板方法”的部分较为类似,都是介绍的模板方法模式。而在前面我们是从重构的角度来使用模板方法模式的,而今天的博客的主题不是重构而是我们的“模板方法模式”。由于篇幅有限,我们的今天的博客就先到这儿,后面还会继续更新其他Swift版的设计模式。

今天博客中的代码在github上的分享地址为:https://github.com/lizelu/DesignPatterns-Swift

设计模式(九): 从醋溜土豆丝和清炒苦瓜中来学习"模板方法模式"(Template Method Pattern)的更多相关文章

  1. 乐在其中设计模式(C#) - 模板方法模式(Template Method Pattern)

    原文:乐在其中设计模式(C#) - 模板方法模式(Template Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 模板方法模式(Template Method ...

  2. 设计模式 - 模板方法模式(template method pattern) JFrame 具体解释

    模板方法模式(template method pattern) JFrame 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考模板方法模式(templ ...

  3. 【java设计模式】【行为模式Behavioral Pattern】模板方法模式Template Method Pattern

    package com.tn.pattern; public class Client { public static void main(String[] args) { AbstractClass ...

  4. 设计模式 - 模板方法模式(template method pattern) 排序(sort) 具体解释

    模板方法模式(template method pattern) 排序(sort) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考模板方法模式(tem ...

  5. 设计模式 - 模板方法模式(template method pattern) 具体解释

    模板方法模式(template method pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 模板方法模式(template metho ...

  6. 二十四种设计模式:模板方法模式(Template Method Pattern)

    模板方法模式(Template Method Pattern) 介绍定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.Template Method使得子类可以不改变一个算法的结构即可重定义该算法 ...

  7. 设计模式 ( 十九 ) 模板方法模式Template method(类行为型)

      设计模式 ( 十九 ) 模板方法模式Template method(类行为型) 1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行 ...

  8. 模板方法模式 Template method 行为型 设计模式(二十六)

    模板方法模式 Template method 上图为网上百度的一份简历模板截图   相信大家都有求职的经历,那么必然需要简历,写简历的时候,很可能你会网上检索一份简历模板,使用此模板的格式,然后替换为 ...

  9. java设计模式 模板方法模式Template Method

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性.毫无疑问,设计模式于己 ...

随机推荐

  1. 异步任务队列Celery在Django中的使用

    前段时间在Django Web平台开发中,碰到一些请求执行的任务时间较长(几分钟),为了加快用户的响应时间,因此决定采用异步任务的方式在后台执行这些任务.在同事的指引下接触了Celery这个异步任务队 ...

  2. 干货分享:让你分分钟学会 JS 闭包

    闭包,是 Javascript 比较重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,很难从定义去理解它.因此,本文不会对闭包的概念进行大篇幅描述 ...

  3. sonn_game网站开发01:写在最前面

    之前做的个人博客项目,日向博客现在已经进入后期完善阶段了.是时候开始打造一个新坑了. 然而改造个什么坑呢?构思了好几天,想了好多方案,都觉得没啥动手欲望.因为,我想做的是那种,自己能用得上,而且有一定 ...

  4. django server之间通过remote user 相互调用

    首先,场景是这样的:存在两个django web应用,并且两个应用存在一定的联系.某些情况下彼此需要获取对方的数据. 但是我们的应用肯经都会有对应的鉴权机制.不会让人家随随便便就访问的对吧.好比上车要 ...

  5. nodejs进阶(5)—接收请求参数

    1. get请求参数接收 我们简单举一个需要接收参数的例子 如果有个查找功能,查找关键词需要从url里接收,http://localhost:8000/search?keyword=地球.通过前面的进 ...

  6. Java 8五大主要功能为开发者提供了哪些便利?

    两年前当Java 8发布后,立即受到了业界的欢迎,因为它大大提高了Java的性能.它独特的卖点是,顾及了编程语言的每一个方面,包括JVM(Java虚拟机)和编译器,并且改良了其它帮助系统. Java是 ...

  7. 学习ASP.NET Core, 怎能不了解请求处理管道[3]: 自定义一个服务器感受一下管道是如何监听、接收和响应请求的

    我们在<服务器在管道中的"龙头"地位>中对ASP.NET Core默认提供的具有跨平台能力的KestrelServer进行了介绍,为了让读者朋友们对管道中的服务器具有更 ...

  8. redis 学习笔记(1)

    redis持久化 snapshot数据快照(rdb) 这是一种定时将redis内存中的数据写入磁盘文件的一种方案,这样保留这一时刻redis中的数据镜像,用于意外回滚.redis的snapshot的格 ...

  9. 记录一次bug解决过程:数据迁移

    一 总结 不擅长语言表达,勤于沟通,多锻炼 调试MyBatis中SQL语法:foreach 问题:缺少关键字VALUES.很遗憾:它的错误报的让人找不着北. 二 BUG描述:MyBatis中批量插入数 ...

  10. Javascript中的valueOf与toString

    基本上,javascript中所有数据类型都拥有valueOf和toString这两个方法,null除外.它们俩解决javascript值运算与显示的问题,本文将详细介绍,有需要的朋友可以参考下. t ...