jeans chen
we've got them by the balls

详细见《C++设计模式 23种设计模式.pdf 55页》

在面向对象系统的分析与设计过程中经常会遇到这样一种情况:对于某一个业务逻辑(算法实现)在不同的对象中有不同的细节实现,但是逻辑(算法)的框架(或通用的应用算法)是相同的。Template 提供了这种情况的一个实现框架。

Template 模式是采用继承的方式实现这一点:将逻辑(算法)框架放在抽象基类中,并定义好细节的接口,子类中实现细节。
【注释 1】Strategy 模式解决的是和 Template 模式类似的问题,但是 Strategy 模式是将逻辑(算法)封装到一个类中,并采取组合(委托)的方式解决这个问题。

模式选择:

Template 模式实际上就是利用面向对象中多态的概念实现算法实现细节和高层接口的松耦合。可以看到 Template 模式采取的是继承方式实现这一点的,由于继承是一种强约束性的条件,因此也给 Template 模式带来一些许多不方便的地方(有关这一点将在讨论中展开)

 

代码说明:
由于 Template 模式的实现代码很简单,因此解释是多余的。其关键是将通用算法(逻辑)封装起来,而将算法细节让子类实现(多态)。

唯一注意的是我们将原语操作(细节算法)定义为保护(Protected)成员,只供模板方法调用(子类可以)。

 

讨论:

其关键点就是将通用算法封装在抽象基类中,并将不同的算法细节放到子类中实现。

继 承 的 强 制 性 约 束 关 系 也 让 Template 模 式 有 不 足 的 地 方 , 我 们 可 以 看 到 对 于ConcreteClass 类中的实现的原语方法 Primitive1(),是不能被别的类复用。假设我们要创建一个 AbstractClass 的变体 AnotherAbstractClass,并且两者只是通用算法不一样,其原语操作想复用 AbstractClass 的子类的实现。但是这是不可能实现的,因为 ConcreteClass 继承自AbstractClass,也就继承了 AbstractClass 的通用算法,AnotherAbstractClass 是复用不了ConcreteClass 的实现,因为后者不是继承自前者。

Template 模式暴露的问题也正是继承所固有的问题,Strategy 模式则通过组合(委托)来达到和 Template 模式类似的效果,其代价就是空间和时间上的代价




Strategy 模式

Strategy 模式和 Template 模式要解决的问题是相同(类似) 都是为了给业务逻辑的,(算法)具体实现和抽象接口之间的解耦。Strategy 模式将逻辑(算法)封装到一个类(Context)里面,通过组合的方式(所以UML图中的菱形是涂黑的,且代码实现中Strategy* _stg的析构是和Context一起的;有的资料上画成白的是错误的)将具体算法的实现在组合对象中实现,再通过委托的方式将抽象接口的实现委托给组合对象实现。State 模式也有类似的功能,他们之间的区别将在讨论中给出。

实现:

*Context类是 Strategy 模式的关键,也是 Strategy模式和 Template 模式的根本区别所在。

Strategy 通过“组合”(委托)方式实现算法(实现)的异构,而 Template 模式则采取的是继承的方式。

这两个模式的区别也是继承和组合两种实现接口重用的方式的区别

 

 

讨论:

可以看到 Strategy 模式和 Template 模式解决了类似的问题,也正如在 Template 模式中分析的,Strategy 模式和 Template 模式实际是实现一个抽象接口的两种方式:继承和组合之间的区别。要实现一个抽象接口,继承是一种方式:我们将抽象接口声明在基类中,将具体的实现放在具体子类中。组合(委托)是另外一种方式:我们将接口的实现放在被组合对象中,将抽象接口放在组合类中。这两种方式各有优缺点,先列出来:

具体参考书籍:XXXX

。。。。。。。

从上面对比中我们可以看出,组合相比继承可以取得更好的效果,因此在面向对象的设计中的有一条很重要的原则就是:优先使用(对象)组合,而非(类)继承(Favor Composition Over Inheritance)。
实际上,继承是一种强制性很强的方式,因此也使得基类和具体子类之间的耦合性很强。
例如在 Template 模式中在 ConcreteClass1 中定义的原语操作别的类是不能够直接复用
(除非你继承自 AbstractClass,具体分析请参看 Template 模式文档) 而组合。(委托)的方式则有很小的耦合性,实现(具体实现)和接口(抽象接口)之间的依赖性很小,例如在本实现中,ConcreteStrategyA 的具体实现操作很容易被别的类复用,例如我们要定义另一个 Context 类 AnotherContext,只要组合一个指向 Strategy 的指针就可以很容易地复用 ConcreteStrategyA 的实现了

 

 



posted on 2013-11-19 17:02  jeans chen  阅读(396)  评论(0编辑  收藏  举报