调侃《Head First设计模式》之模板方法模式

来源:互联网 发布:mac有格式工厂吗 编辑:程序博客网 时间:2024/04/29 18:35

      现在有两个人,一个爱喝咖啡,一个爱喝茶,让我们用代码创建咖啡和喝茶:

     咖啡类:

    

     茶类:

    

     很容易发现,咖啡喝茶的代码有惊人的相似。

     经过之前设计模式的阅读,你应该已经有意识的把相同的部分抽取出来。pourInCup和boilWater方法相同,于是可以考虑将它们整合到一个公共的类中,我们可以这样设计:

     

      CaffeineBeverage是一个公共类,咖啡喝茶是它的子类,继承了相同的方法。

     等下,难道相同的部分就这样?no。

    

     brewCoffeeGrinds()和steepTeaBag()两个方法,一个是冲泡,一个是浸泡,其实差不多的,是不是也考虑抽取出来呢?对于addSugerAndMilk()(添加糖)和addLemon()(添加柠檬)是不是也一样?

    我们使用brew()表示 brewCoffeeGrinds()和steepTeaBag(),使用addCondiments()表示addSugerAndMilk()(添加糖)和addLemon()吧。

   公共类的代码可以为:

   

     现在具体的咖啡喝茶类只需实现泡和添加调料两个方法就行了:

    

   对比之前第一份代码的咖啡喝茶是不是节省了很多代码?以后有类似的饮料扩展起来也容易多了,防止出现大量重复代码。

   

  其实以上使用的是模板方法设计模式

 在上面的例子中,模板方法就是prepareReceipe()。

  CaffeineBeverage类主导着这个冲咖啡喝茶的算法流程,将代码的复用几乎做到了最大化,新增加饮料类型不需要添加太多代码,只需实现和其他饮料不同的方法即可。

 总的来说,可以说CaffeineBeverage提供了一个框架,它专注于算法本身,由子类提供完成的实现。

  

 我们来看看官方的定义:

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

   看下类图:

   

    模板方法templateMethod()会调用primitiveOperation()1和primitiveOperation()2,它不关心这两个方法的实现,从而实现了模板方法和一些具体子类操作的解耦。

   在Java API中,使用模板方法模式的典型例子当属排序。如果我们对整形数或者浮点型数据进行排序,那只要知道排序是从小到大还是从大到小就可以排序,如果叫你对一组对象排序呢,你可能就会问,对象如何比较大小呢。

   是的,对象间无法直接比较大小,所以Java提供了Comparable接口,里面有个CompareTo方法,每个需要排序的类都要实现这个接口,在CompareTo方法中实现具体的排序手段,比如排序一群猫,你可以以猫的体重为标准排序,也可以以身高等。这样就创建了一个可以供排序的类,然后将该类对象的数组传入Array类的静态方法sort,就可以根据CompareTo方法制定的排序标准来排序啦。现在引入一群鸭子的排序例子:

     

    鸭子类的创建,实现Comparable接口的CompareTo方法,让其可排序,以体重大小为排序的方式。

   客户端程序:

   

     Array的sort方法实现:

     

    Comparable接口类似于之前CaffeineBeverage的功能,将具体的排序方法CompareTo方法延迟到子类实现,因为不同的子类排序标准肯定不同。这样Array的sort方法就可以对任何实现Comparable的类对象进行排序。

    

   会不会觉得模板方法模式和之前哪个模式很像呢?没错,就是工厂方法模式,可以说,工厂方法模式是一种特殊的模板方法模式。

0 0
原创粉丝点击