2. Mixin
附件:
您所在的用户组无法下载或查看附件如上图所示,增加了Quackable和Squeakable两个接口,相当地简单直接。
源代码下载:

附件:
您所在的用户组无法下载或查看附件(VS2008控制台工程)
Strategy和Mixin,你喜欢哪一个呢?
Strategy会使概念更集中一些——只要看一下Duck抽象类中都有哪些函数,对整个类层次就了解得差不多了;而且,FlyBehavior都有哪些实现方式也一目了然。统一的宽接口使得Client代码简单而一致。特别地,Strategy允许运行期动态更换FlyBehavior和QuackBehavior的实现,这是.net里的Mixin做不到的。
如果你是窄接口的拥护者,那么很可能会选Mixin了。不过看一下上面那个图,会有一种散和乱的感觉。Mixin更适合实现比较独立的概念,或是XXUtility这种东西。Mixin给人的感觉是简单、直接、轻巧。
Mixin 和 Template MethodMixin非常适合用来实现“无论你是谁,只要提供了CompareTo()函数,就可以立即免费获得LessThan()、GreaterThan()、EqualTo()、LessEqual()和GreaterEqual() 这5个非常有用的函数”这样的语义。

附件:
您所在的用户组无法下载或查看附件Client代码:
IList<Duck> ducks = new List<Duck>();
MallardDuck duck1 = new MallardDuck(1);
MallardDuck duck2 = new MallardDuck(2);
MallardDuck duck3 = new MallardDuck(2);
Console.WriteLine("duck1 < duck2 ? {0}", duck1.LessThan(duck2));
Console.WriteLine("duck1 > duck2 ? {0}", duck1.GreaterThan(duck2));
Console.WriteLine("duck1 < duck3 ? {0}", duck1.LessThan(duck3));
Console.WriteLine("duck2 <= duck3 ? {0}", duck2.LessEqual(duck3));
源代码下载:

附件:
您所在的用户组无法下载或查看附件(VS2008控制台工程)
以前,要想实现同样的语义只能用Abstract Class。

附件:
您所在的用户组无法下载或查看附件单以这个例子来看,使用Mixin有许多优点。首先,我们提炼出了一个明确、独立、通用的概念IComparable。其次,IComarable+CompareModule重用性更好。在这个例子中,由于IComarable+CompareModule里面的内容并不是领域相关的,所以就更应该将其提炼出来,这样Mallard Duck就可以集中精力处理领域相关的问题,程序的结构更加清晰,可读性更好。
不过上面那个例子并不能算得上是真正的Template Method模式。真正的Template Method模式是将所有子类共有的完成某项任务的算法提炼到父类中固定下来,子类只负责实现算法中的一个部分,不需要操心整个算法的所有步骤以及进行这些步骤的先后顺序和条件。就像说把大象装冰箱统共分三步,其实把猪装冰箱也统共分三步,把任何东西装冰箱都是分三步,这样我们就发现了一个可以提炼出来的算法“装冰箱”。
我们提炼出概念或算法不仅仅是为了“代码”重用——少些几行代码,仅仅是节省了一点儿体力而已。更为重要的是,我们想要节省脑力——对于已有代码,可以更快、更深刻地理解;如果需要新增代码,不需要把所有的逻辑再想一遍。
沏茶和泡咖啡的方法很相似,都要先烧水,然后把茶或速溶咖啡放入杯子,再倒满水。而且都需要考虑不少的细节,比如沏茶要用80度的水,泡咖啡用95度的最好;沏茶的话可以加两朵菊花,泡咖啡可以多加些糖;茶是可以直接加水续杯的,而咖啡不能续杯……如果有一天我想喝黑芝麻糊,难道必须再把所有的细节再想一遍?在现实生活中没有办法,但是在编程世界里就可以使用Template Method模式来逃避这烦人的工作。

附件:
您所在的用户组无法下载或查看附件活在编程世界是不是比现实世界要轻松些?
不过本文并不是想讲述Template Method的诸多好处,而是想问一个问题:用Mixin的方式代替Abstract Class实现Template Method模式是否更好?一个明显的好处是可以不受.net单继承的限制。
.net 只允许单继承,一个类只能继承一个Abstract Class,有时这的确挺不爽的。比如要实现一个“黑芝麻糊及刨冰一体机”,以前只能使用组合的方法。

附件:
您所在的用户组无法下载或查看附件而如果使用Mixin,就能使用多继承了。

附件:
您所在的用户组无法下载或查看附件等一等,多继承不是复杂与混乱之源么?是的,在C++中使用多继承确实存在许多陷阱和禁忌[3]。造成多继承复杂性的主要原因是属性和函数的模棱两可(ambiguity)问题——如果子类所继承的多个父类中有同名的函数或属性,当子类重载这些函数或Client代码想要调用这些函数时,编译器会不知道应当重载或调用哪个父类的函数。经过多年的实践和讨论,人们意识到必须对多继承做一些限制以减少造成混乱的可能性。.net中的Interface+显式实现接口正是这样一个简单而优雅的折中方案。现在,.net又稍稍放宽了限制,允许使用Interface+Extension Methods的方式多继承非虚函数,使得.net中的多继承功能更强大了一些。
Template VS Freedom你会害怕使用继承么?你是否曾对Template Method模式充满恐惧?我曾经觉得把子类的核心算法提升到父类中固定下来是一个疯狂的想法。继承会造成子类对父类强烈的依赖,特别是使用Template Method模式的时候,子类将受到父类强大的束缚。我不喜欢束缚,我喜欢自由。特别是我还铭记着“组合优于继承”的设计原则。于是我分离出了一个又一个XxxUtility和Xxxxxxer,于是我的Abstract Class成了空壳。后来,我突然发现每次增加子类都要把所有的实现步骤和细节全部重新想上一遍同样十分恐怖,特别是有50多个子类等着你去添加的时候。继承使得子类对父类产生很强的依赖,这可以看作是缺点,但是也可以说,父类对子类有很强的“控制力”(特别是在使用Template Method模式的时候),使得子类简单而又整齐划一,就像同一个模子里铸出来的锡兵一样。幸运的是,继承和组合并不是一个非此即彼的抉择,我们可以在纪律和自由之间折中。把子类的核心算法提升到父类中形成Template Method模式,把其它的重复代码提炼出来形成Strategy或Mixin再使用之。不用害怕,没有人可以在一开始设计的时候就做出完美的提炼,除非他以前作过类似的程序或者是个不折不扣的先知。
参考文献[1] Freeman et al, Head First Design Patterns. O’Reilly, 2004.
影印版:深入浅出设计模式(英文影印版)。东南大学出版社,2005。
[2] Thomas et al, 孙勇等 译, Programming Ruby 中文版。电子工业出版社,2007.
[3] Meyers,侯捷 译, Effective C++ 中文版。华中科技大学出版社,2001. ——条款43:明智地运用多继承。