1. 程式人生 > >Stroller

Stroller

 

委託比繼承靈活,可以動態配置,不會造成子類級數增長,另外可以通過物件的合成來實現多種功能(Decorator)

繼承則相對不靈活,一旦選擇了子類後,不能動態配置

委託是黑盒重用(看不到父類方法),繼承是白盒重用,應該多使用委託少用繼承

繼承打破封裝。因為子類的實現與父類的實現關係密切,所以父類實現的任何改變將引起子類的變化。

讓重用機制發揮作用

多數人能夠理解物件、介面、類、繼承等概念。然而,真正的挑戰在於應用這些概念來構建靈活、可重用的軟體。設計模式告訴你如何做到這一點。

繼承VS合成

在面向物件系統的功能重用過程中,兩個最普遍的技術就是類的繼承和物件合成。我們之前解釋過,類的繼承讓你能通過某個類的實現定義另外的類的實現。通過子類實現的重用通常指“白盒重用”。術語“白盒”指的是可見性:通過繼承,父類的內部結構對子類來說是可見的。

物件合成是類繼承的替代選擇。通過彙編或合成物件可以獲得新的功能。物件合成需要用來進行合成的物件具備良好定義的介面。這種型別的重用被稱為“黑盒重用”,因為物件的內部細節是不可見的。

繼承和合成都有各自的優缺點。類的繼承是在編譯時靜態定義的,且由於語言的直接支援,可直接實現。類繼承也使得可以較易的在重用時修改實現,當子類過載部分而不是所有的操作時,它同樣可影響其繼承而來的操作(在使用了過載的情況下)。

類繼承也有一些缺點。首先,由於繼承在編譯時完成,因此,不可能在執行時改變繼承自其父類的實現;其次,更糟的是,父類通常定義了其子類的部分物理表示。因為繼承向子類暴露了父類的實現細節,故有這樣的說法繼承打破封裝

。因為子類的實現與父類的實現關係密切,所以父類實現的任何改變將引起子類的變化。

當你試圖重用一個子類時,這種實現依賴可能會產生問題,由於通過繼承得到的實現不可能在每個方面都適合新的問題領域,故父類可能會要更改或重寫。這種依賴限制了靈活性,並最終限制了可重用性。解決的方案是僅僅通過抽象類來繼承,因為抽象類通常提供很少的實現、甚至根本沒有任何實現。

物件合成是物件通過獲得其他物件的引用,而在執行時動態完成的。合成需要物件表明各自的介面,這需要小心的設計介面,以利物件可與其他更多物件一起使用。因為物件通過其介面進行訪問,我們不必打破封裝。只要擁有同一型別,任何物件都能在執行時替換為另外的物件。而且,因為物件的實現是根據其介面而編寫,這將減少實現依賴。

物件合成在系統設計中還有另外一個效果。任用物件合成能幫助你保持類的封裝而可專心處理一項任務。你的類和類層次將保持較小,很少出現變成難以管理的層次大怪。另一方面,基於物件合成的設計中將擁有更多的物件(在更少的類的情況下),系統的行為將決定於它們之間的相互關係,而不是在一個類中定義。

這裡匯出了我們的第二個面向物件設計原則:

優先採用物件合成來代替類繼承

理想情況下,你應該在不必編寫新元件的情況下達成重用,你應當可以通過物件合成來組裝存在的元件而得到所需的功能。但這種情況很少,因為在實踐中可獲得的元件集並不十分豐富。

根據我們的經驗,設計中採用繼承作為重用技術的情況有些過濫,其實,在設計中更多的任用物件合成技術將帶來更好的可重用性。在設計模式中,你將看到一次又一次的物件合成應用。

委託

委託是使得合成技術在重用中完成和繼承一樣功能的一個辦法。在委託中,當處理請求時,涉及到兩個物件:接收者物件委託其操作給委託人物件(代表)。一個類比是子類處理髮給父類的請求。但是,在繼承中,繼承而來的操作總可以通過this成員變數指向接收者物件;而在委託中,為了達成同樣的效果,接收者將自己傳遞給委託人,以讓被委託的操作指向接受者。

例如,代替將視窗類作為矩形類的子類的方案,視窗類可以通過保持一個矩形例項變數,並將矩形的詳細行為委託給它,而重用矩形類的行為。換句話說,“視窗是矩形”的替代方案是,“視窗可以作為一個矩形”。應用委託,視窗物件可以明確的傳送請求給其矩形物件例項;而如果不採用委託,它可能必須繼承這些操作。

委託的主要優點在於,可以容易的在執行時合成(compose)行為並改變其合成方式。假設矩形類和圓類擁有同樣的型別,我們的視窗可以在執行時變成圓,只需通過用圓例項替換矩形例項。

委託與其它通過物件合成來增強軟體靈活性的技術一樣,都有一個共同的缺點:動態、高參數化的軟體與相對靜態的軟體相比,比較難以理解。另外,委託也存在執行時效率問題。只有當運用委託的簡化性超過其複雜性的情況下,委託才是一種好的設計選擇。很難說明何時運用委託,因為其效率取決於其應用環境,而對效率的判斷取決於設計者運用它的經驗。最好的應用委託的情況是當它運用於高度程式化的環境----即,在標準模式中。

有幾個設計模式應用了委託,如狀態模式、策略模式、和訪問者模式。在狀態模式中,一個物件委託其請求給狀態物件,狀態物件表示了它的當前狀態;策略模式中,一個物件委託一個詳細請求給另外一個表示攜帶請求的策略的物件;一個物件只有一個狀態,但可以有多個針對不同請求的策略,這兩個模式的目的都是為了通過改變委託請求的物件,而改變物件的行為。在訪問者模式中,對物件結構的每一個元素的執行操作總是委託給了訪問者物件。

在其他的模式中委託的應用,沒有在上述模式中那麼重要。解調器模式用一個物件去協調其它物件的通訊,解調器物件有時簡單的直接用其它物件執行操作,有的時候,它提交一個對自身的引用,此時真正運用了委託;責任鏈物件通過將請求沿著物件鏈從一個物件傳到另外一個,從而處理請求。有時,請求攜帶了一個接收請求的原始物件的引用,此時,該模式運用了委託;橋接模式分離了實現與其抽象,當抽象和特定實現匹配時,抽象可簡單的委託對具體實現的操作。

委託是物件合成的一個特例。這說明,為了程式碼重用,總能用物件合成機制來替換繼承。

相關推薦

Stroller

  委託比繼承靈活,可以動態配置,不會造成子類級數增長,另外可以通過物件的合成來實現多種功能(Decorator) 繼承則相對不靈活,一旦選擇了子類後,不能動態配置 委託是黑盒重用(看不到父類方法),繼承是白盒重用,應該多使用委託少用繼承 繼承打破封裝。因為子類的實現