[转录]Re: Inheritance (继承)

楼主: sorryChen (陈扬和)   2008-11-20 03:07:17
※ [本文转录自 Programming 看板]
作者: tinlans ( ) 看板: Programming
标题: Re: Inheritance (继承)
时间: Wed Nov 19 11:00:04 2008
※ 引述《sorryChen (陈扬和)》之铭言:
: 其实我不懂什么时候才真正应该用继承..
: 我的用法只是把继承structuralize我的code.
重构 (refactoring) 上也常单纯是把继承拿来这样用,
其实也没有什么不对,
这个看重构的书就会看到一大堆类似的例子。
: 比如说我要设计一台跑车的class.
: 我就先设计"交通工具"此class..再设计车这个class 继承交通工具
: 在设计"跑车"继承"车", 虽然其实所有的class都是我写的
: 而且目前我只需要跑车.. 这个物件 但因为这个物件有许多
: memeber function 和 variables 我是靠继承来把code在功能上
: 分的比较清楚..我还使用多重继承 来让一个class有多个class的member
: 和function.
你的目的显然是 reuse 已经撰写过的 code,
但是 reuse 已经写过的 code 并不是非继承不可,
一般 OO 的书会建议你尽量使用合成 (composition) 取代继承,
也比较提倡以责任委派 (delegation) 取代继承。
你的状况是需要把“行为”本身抽离出来 (就是你想 reuse 的 member functions),
建立一个或一组行为家族的继承体系,
车子本身负担的责任就不再包含这些被你抽离的行为,
而是将责任委派给行为物件。
譬如代表 A 类行为继承体系里的 base class 是 BehaviorA,
程式码就可以写成下面这样:
class Car {
public:
void setBehavior(BehaviorA *behaviorObj) { behaviorObj_ = behaviorObj; }
void doSomething() { behaviorObj_->doSomething(); }
private:
BehaviorA *behaviorObj_;
};
Car::doSomething() 做的事情就很单纯是把任务委派给其它物件,
它本身并不会做任何事情,
至于委派给什么物件有很多做法,
这里的做法是让 Car 和 BehaviorA 家族里的某物件产生“关联”,
而建立这种关联性的方式是采用“合成”的方式,
也就是将 BehaviorA 成为 Car 的一个 data member。
在 OO 的术语里面还会区分聚合 (aggregation) 跟合成,
像是上面的写法其实应该叫做聚合,
因为 Car 不主掌 BehaviorA 家族物件的生命周期,
近代 C++ 会以 shared_ptr<BehaviorA> 来更明确的表现聚合概念;
如果你想明确的表现合成概念,
其中一种方法就是在 Car 的建构子里产生 BehaviorA 家族里的物件,
然后在解构子里明确的把它 delete 掉。
: 现在被说这样做很不好, 误解了inheritance的真意
: 而且能尽量不用继承最好...我想版友们一定会叫我去看书
也不是不用最好,
只是如果用的是 public 就要遵循 Liskov Substitution Principle,
否则 user 用起来感觉会很不直觉,
比方说你让正方形继承矩形看似合理,
但是可以考虑下面的例子:
Rectangle *shape = makeRectangle(); // 任意产生矩形“家族”的物件
int originalHeight = shape->height();
shape->setWidth(10);
assert(shape->height() == originalHeight);
如果正方形也被归类在矩形家族里,
那么上述的 assert 就有可能发生失败,
这是因为正方形的 setWidth() 做的事情比矩形保证的还多,
造成家族物件行为上的不一致,
这种状况就是违反 LSP 的其中一个例子。
当然你高兴用 private 或 protected 继承就不会有这个问题,
不过你将来很可能会遇到语言无法提供“动态继承”的问题,
也就是说物件之间的继承关系无法在 runtime 切断和重新建立,
这时也只有合成和委派能达成相同的目的。
LSP 只有在纯 OO 程式才有意义,
如果你是要搭 generic programming 之类的 paradigm 那又是另一回事,
在那边的世界里违背 LSP 的 public 继承,
以及 OO 领域很不喜欢的多重继承会变得随处可见,
详情可参考 Modern C++ Design 之类的书籍。
: 我看来看去还是看不懂为什么不好
: 请原谅我没看过pattern design但是有没有大师可以指点一下
书还是要读,
不然可能很多东西会解释不完。

Links booklink

Contact Us: admin [ a t ] ucptt.com