May 25

设计原则: 多用组合,少用继承。 不指定

felix021 @ 2009-5-25 14:28 [IT » 探索设计模式] 评论(2) , 引用(0) , 阅读(10820) | Via 本站原创 | |
前些天在《Head First设计模式》上看到了这一原则。
书上的例子非常好,鸭子的飞行行为和嘎嘎叫的行为确实可以从父类继承得到
但是如果出现橡皮鸭子,它不会叫也不会飞,如果要把它归类为鸭子,那么代码就有得写了(更详细内容参见该书)。

今天突然想起另外一个问题,某天看到一句话:Java采用接口,避免了多继承带来的问题。
于是去Google了一下多继承存在的问题,然后就发现,除了继承带来的冗余数据和方法之外,另一个大问题就是钻石问题。
@ 2009-05-26 下面举的例子有点问题,详情参见篇后sandy的评论
话说端午节快到了,该是吃粽子的时候了——
我们知道米饭和豆沙都是(继承)食品,然后我们用米饭包住豆沙放在锅里蒸一下,我们就得到了(派生)粽子。
这样的结构是:
    食品
    /     \
米饭   豆沙
    \     /
     粽子
这是一个菱形,于是被成为钻石问题:如果食品里有一个成员 "好吃程度",那么粽子的"好吃程度"是继承自哪一个呢?
在C++这个支持多继承的语言里面,如果直接使用
粽子 粽子a;
cout << 粽子a.好吃程度 << endl;

然后就会发现编译器(g++)报错:对成员"好吃程度"的请求有歧义(ambiguous)。
不过好在有3个解决方式:
1。重新定义一个好吃程度覆盖米饭和豆沙的好吃程度。
2。指明是哪个父类的好吃程度:例如  粽子a.米饭::好吃程度  或者  粽子a.豆沙::好吃程度
3。使用虚拟继承(虚基类),详情请STFW。

于是我突然想到其实这里如果使用"多用组合,少用继承"的设计原则(很像解决方法2),那么问题就解决拉:
class 粽子: public 食品{
private:
    米饭 米饭a;
    豆沙 豆沙a;
public:
    粽子(){
        好吃程度 = (米饭a.好吃程度 + 豆沙a.好吃程度) / 2; //其实我觉得豆沙a的权值应该大些=.=
    }
};

当然这只是一个很初步的想法,代码也非常不严谨,谨以此抛砖引玉,欢迎交流。

转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: http://www.felix021.com/blog/feed.php
sandy
2009-5-26 18:16
我觉得你对OO的经验还很不够。

OO应用的一个基本问题就是要正确判断is-a关系还是has-a关系。
像粽子那个例子很明显应该是has-a关系,就不应该使用继承机制。

"多用组合,少用继承"——这种所谓的原则其实根本不算原则,到底什么时候该用继承什么时候该用组合最本质的决定依据还是上述关系判断,该用继承的时候就是继承,你换成组合来避免所谓的“钻石问题”只能失掉大量OO特性而已——你回头看看,其实你会发现采用组合并没有解决任何问题,只是换了种写法而已(.操作符换成了::操作符而已)。
felix021 回复于 2009-5-26 18:55
嗯,我在写的时候也觉得这个例子不太好,主要是因为端午节近了。。。
如果举华裔美国人的例子可能更合适一些,不过那样组合就也不太好了。

其实那个组合原则是定义多个实现同一个接口的算法族类,
然后用不同算法族里的一些类组合成新的类,以达到更佳的伸缩性,和这个是有点不一样。
我应该重新组织一下,嗯。
p.s. 这个粽子有一点点像外观模式grin
fl
2009-5-26 00:51
好书
好粽子
felix021 回复于 2009-5-26 00:52
@_@
分页: 1/1 第一页 1 最后页
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   *非必须
网址   电邮   [注册]