目录
模板方法模式
在本章一开始的例子里,使用到了星巴兹咖啡冲泡法和星巴兹茶冲泡法。这两种冲泡法都采用了相同的算法,如何来实现抽象这个算法。
思考:抽象类与接口的区别?设计时应该如何注意?
将完全相同的部分作为Base Class中的Method,然后将特异性的部分作为abstract方法。
模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现。
模板方法模式在一个方法中定义一个算法框架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
模板也是一个方法。更具体地说,这个方法将算法定义成一组步骤,其中的任何步骤都可以是抽象的,由子类负责实现。这可以确保算法的结构保持不变,同时由子类提供部分实现。
对于模板类(抽象的父类)中的final方法,子类无法覆盖。它可以被模板方法直接使用或者被子类使用。在模板中我们也可以定义“默认不做事的方法”,方法的函数体实现为空。我们称这种方法为”hook”(钩子)。子类可以视情况决定要不要覆盖它们。
有了钩子,我能够决定要不要覆盖方法。如果我不提供自己的方法,抽象类会提供一个默认的实现。
当子类必须提供 算法中的某个方法或者步骤的实现时,就应该使用抽象方法。如果算法的这个部分是可选的,就要用钩子。如果是钩子的话,子类可以选择实现这个钩子,但并不强制这么做。
使用钩子的真正目的:钩子可以让子类实现算法中可选的部分,或者在钩子对于子类的实现并不重要的时候,子类可以对此钩子置之不理。钩子的另一个用法是,让子类能够有机会对模板方法中某些即将发生的(或刚刚发生的)步骤做出反应。
在设计模板方法时,要保持抽象方法的数目越少越好。让算法内的步骤不要切割得太细,但是如果步骤太少的话,会比较没有弹性,所以要看情况折衷。
设计原则:好莱坞原则
别调用(打电话给)我们,我们会调用(打电话给)你。
这实际上是组件的分层思想,高层组件会决定什么时候和怎样使用这些低层组件。换句话说,高层组件对待低层组件的方式是“别调用我们,我们会调用你”。
因此,低层组件绝对不可以直接调用高层组件,但是高层组件可以控制何时以及如何让低层组件参与。
好莱坞原则和第4章的依赖倒置原则的关系: 依赖倒置原则教我们尽量避免使用具体类,多使用抽象类。好莱坞原则是用在创建框架或组件上的一种技巧,好让低层组件能够被挂钩进计算中,而且又不会让高层组件依赖低层组件。两者的目标都在于解耦,但依赖倒置原则更加注重如何在设计中避免依赖。
低层组件可以调用高层组件中的方法。事实上,低层组件在结束时,常常会调用从超类继承来的方法。但是我们在设计时要避免高层组件和低层组件之间有明显的环状依赖。
模板方法与策略模式的异同
策略模式定义一个算法家族,并让这些算法可以互换。正因为每个算法都被封装起来了,所以客户可以轻易地使用不同的算法。
模板模式的意图是定义一个算法的大纲,由它的子类来定义其中某些步骤的内容。这么一来,算法中的个别步骤可以有不同的实现细节,但是算法的结构依然保持不变。
策略模式并不是使用继承来进行算法实现的,而是通过对象组合的方式,让客户可以选择算法实现。
模板方法中重复使用到的代码,被放进了超类中,好让子类共享。
策略模式使用对象组合,更具有弹性。利用策略模式,客户可以在运行时改变他们的算法。客户只是改变不同的策略对象罢了。
总结,模板方法和策略模式都封装算法,一个用组合,一个用继承。
工厂方法是模板方法的一个特殊版本。
- 模板方法:子类决定如何实现算法中的某些步骤
- 策略模式:封装可互换的行为,然后使用委托来决定要采用哪个行为
- 工厂方法:哪个具体类