[轉錄]Re: Inheritance (繼承)

看板OOAD作者 (陳揚和)時間16年前 (2008/11/20 03:07), 編輯推噓0(000)
留言0則, 0人參與, 最新討論串2/2 (看更多)
※ [本文轉錄自 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但是有沒有大師可以指點一下 書還是要讀, 不然可能很多東西會解釋不完。 -- Ling-hua Tseng (uranus@tinlans.org) Department of Computer Science, National Tsing-Hua University Interesting: C++, Compiler, PL/PD, OS, VM, Large-scale software design Researching: Software pipelining for VLIW architectures Homepage: https://www.tinlans.org -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 118.160.110.248

11/19 16:57,
感謝大師的指點
11/19 16:57

11/19 17:31,
再次拜謝
11/19 17:31
-- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 128.125.87.33
文章代碼(AID): #1996FcLV (OOAD)
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 2 之 2 篇):
文章代碼(AID): #1996FcLV (OOAD)