代码重构(五):继承关系重构规则(组图)
今天是五.第四个青年节土豆丝教案模板范文,祝大家节日快乐。今天看标题,有胃口。夏天到了。醋土豆丝和炒苦瓜适合夏天吃,但不好吃。这两个菜应该很多人都吃过,尤其是醋土豆丝。作为“鲁菜”的代表作之一,为大众所熟知。醋土豆丝不好吃。炒苦瓜是一道好菜,是夏天必备的一道菜,它的功效在此不再赘述。言归正传,在之前的博客中,我们从“小哥哥”那里学到了“外观模式”,我们也将“外观模式”戏称为“小弟弟模式”。
说到模板方法模式,如果你看过之前发布的重构相关的博客,你应该对模板方法模式很熟悉。在博客“代码重构(五):继承关系重构规则”)的第三部分中,实际上使用了“模板方法模式”进行重构,在重构规则中,我们称之为“表单模板方法” (构造性模板函数)”,这个模板函数就是本篇博客中的模板方法。今天我们要从另一个角度来看“模板方法模式”,从“醋土豆”和“清除”来了解一下“ 《炒苦瓜》制作实例中的模板方法模式。在本博客中,您不仅是程序员,也是厨师。
老规矩,在博客的开头,我们首先给出了“模板方法模式”的定义。如果你是新手,看不懂定义也没关系,因为定义一般很难理解。看完下面的具体例子,你可以回顾一下这个定义。模板方法的定义如下:
模板方法模式:一个算法的骨架定义在一个方法中,一些步骤延迟到子类。模板方法允许子类在不改变算法结构的情况下重新定义算法中的某些步骤。
一、开始做饭
接下来,我们将开始制作我们的醋土豆丝和炒苦瓜。当然,在这篇博客的第一部分,我们不会使用我们的模板方法来炒。本节我们先给出常规的烹饪方法,然后再进行分析,最后使用我们的“模板方法模式”进行烹饪。当然,这里我们并不是真的用锅做饭,而是用我们的代码做饭然后走开。
1.炒一个醋土豆丝
接下来,我们要炒一个醋土豆丝。醋土豆丝味道鲜美,制作简单。再次土豆丝教案模板范文,醋土豆丝不好吃。因为我们一节课就煎完了“醋土豆丝”,这里就不画类图了。模板方法模式发出后,会给出相应的类图。下面的 FryShreddedPotatoes 类别是我们制作“醋土豆”的类别。它给出了制作醋土豆丝的一系列步骤,并将这一系列函数组合在了fryShreddedPotatoes()函数中。
有了上面完成的类,我们就可以实例化上面的类,调用fryShreddedPotatoes()炸一盘醋土豆丝。下面我们将实例化FryShreddedPotatoes,然后炒一盘醋土豆丝。
2、 这是一盘“炒苦瓜”
上面的土豆丝就完成了,出锅了。接下来,我们要上一盘“炒苦瓜”。当然,“炒苦瓜”的做法不如上面的“醋溜土豆丝”,但有些步骤还是有区别的。当然,炒苦瓜的时候不能放醋,炒苦瓜的时候放苦瓜片而不是土豆丝。这些都是不同的。当然这两道菜的名字是不同的。下面这个类是我们的“炒苦瓜”类,你可以实例化这个类,然后自己制作一盘自己的炒苦瓜。一般来说,下面的代码和我们上面的醋土豆丝的步骤类似,只是具体的细节和一些步骤调用的方法不同。
下一步就是实例化上面的“炒苦瓜”这个类别,然后来一盘炒苦瓜。下面是我们创建的上述类的对象,然后调用炒苦瓜的方法。下面是调用方法和输出结果。经过下面的过程,我们就可以煮出一锅苦瓜了,如下图:
二、用“模板法”做饭
在以上两种烹饪方式中,不难看出炒醋土豆丝和炒苦瓜这两个类别中存在大量重复代码。在我们重构系列的博客中,我们提到过记得重复代码,所以我们需要对上面两个类的代码进行重构,而重构的方式就是使用“模板方法模式”进行重构。本质上,它将改变的部分与不变的部分分开。在本例中,变化的部分是某些步骤的具体细节,不变的部分是执行步骤的内容和部分步骤。
在这个烹饪示例中,整个烹饪过程没有改变,过程中的一些步骤也没有改变。改变的是报菜名的方法报菜名不同,然后炒的菜不一样,一个是土豆丝炒,一个是苦瓜炒,最后添加的调味料是不同的。在这样的分析中,我们可以将不变的方法放在父类中,将烹饪的不变步骤封装成一个“模板方法”,在扩展中可以实现某些不变的步骤(如放油等)。这部分的代码结构稍微复杂一些,我们给出相应的类图。
1. 重构后的类图如下(使用“模板方法模式”)
首先,我们给出重构后的类图。使用“模板方法模式”重构的类图如下所示。FryVegetablesType 是我们创建的一个烹饪协议,它定义了“醋土豆丝”和“炒苦瓜”的所有方法,但我们对两者的不同方法进行了重命名,使它们统一起来。因为两种不同的方法实现的东西基本相同,比如之前炒苦瓜中的putBitterGourd()方法,我们就改名为“放菜”的putVegetables()方法。putVegetables()方法也可以用在“醋炒土豆丝”中,因为putVegetables()把苦瓜放在“炒苦瓜”里,土豆丝放在炒土豆丝里。
在 FryVegetablesType 协议的扩展中,我们给出了相同的默认实现,比如模板方法(fry())、putSomeOil())、放一些葱花(putSomeGreenOnion())、outOfThePan()等。这两道菜的外延炒法是一样的。我们在炸土豆丝和炸苦瓜中实施的方法是不同的。类图如下:
2.Cooking接口和接口扩展代码实现
根据上面的类图,我们可以给出烹饪接口的代码实现和接口的扩展。接下来要做的是将不变的部分提取到接口和接口的扩展中。下面是我们提取的炒菜的接口 FryVegetablesType 以及接口的对应扩展。FryVegetablesType协议给出了模板方法fry()和烹饪的步骤(即烹饪的算法)。在这个接口的扩展中,模板方法fry()的默认实现调用了这些步骤,并给出了一些未改变的步骤的实现。具体代码如下:
3.“醋土豆丝”和“炒苦瓜”的具体实现
下面的代码片段是在模板方法模式下醋土豆丝和油炸苦瓜的代码实现。从下面的代码不难看出,它们都遵循了 FryVegetablesType 协议,并且都有协议的默认扩展。我们知道,默认扩展中的代码类似于抽象类的默认实现,是由子类共享的,所以下面的两个类只给出了不同的步骤。例如,醋土豆丝里放的调味品是盐和醋,而炒苦瓜里放的调味品是盐。当然,两个子类中实现的另外两个方法也不同。不管子类如何给出默认实现的步骤,我们在默认扩展中给出的模板方法是不变的,即,具体的烹饪步骤是一样的。这是模板方法模式。模板方法不关心每个步骤的具体细节,而只关心步骤执行的顺序。这就是封装了算法的所谓模板方法,而不是具体的计算细节。
使用模板方法的一个明显好处是减少代码冗余并将更改的部分与未更改的部分分开。在这个例子中,未改变的部分放在协议的默认扩展中,改变的部分放在子类中。这就是“模板方法模式”。
4、“模板方法模式”的测试用例
接下来,我们要测试上面的例子。下面是我们模板方法的测试用例。其实下面的测试用例和之前没有使用模板方法时的测试用例类似,只是炒的方法不同。虽然在调用的方法上有一些区别,但这里的区别只是函数名称的不同,函数的作用没有变化。下面是我们重构代码的测试用例和运行结果。从结果可以看出,和我们之前没有使用模板方法的测试用例的输出结果是一致的。这就是我们在“重构”系列博文中经常提到的,在不改变代码的外部调用接口的前提下,改变代码的内部结构。
本篇博客类似于我们之前类重构的“构建模板方法”部分,都是介绍的模板方法模式。上一节我们从重构的角度使用了模板方法模式,今天博客的主题不是重构而是我们的“模板方法模式”。由于篇幅有限,今天的博客先发到这里,后续会继续更新其他Swift版本的设计模式。
今天github上博客中代码的分享地址是:
您为光棍出了很好的主意