1.概念解析php
面向對象編程的單一職責原理(SPR-Single Responsibility Principle)規定對象只能有一個職責。就一個類而言,應該僅有一個引發它變化的緣由。 爲何要把不一樣的職責分配到不一樣的類中呢?由於每個職責都是變化的一個軸線,當需求變化時,該變化會反映爲類的職責的變化。若是一個類承擔了多於一個的職責,那麼就意味着引發它的變化的緣由會有多個。若是一個類承擔的職責過多,那麼就等同於把這些職責耦合在了一塊兒。一個職責的變化可能會抑制到該類完成其餘職責的能力,這樣的耦合會致使脆弱的設計。當變化發生時,設計會受到意想不到的破壞。html
這個原則的核心含意是:一個類應該有且僅有一個職責。關於職責的含意,面向對象大師Robert.C.Martin有一個著名的定義:所謂一個類的職責是指引發該類變化的緣由,若是一個類具備一個以上的職責,那麼就會有多個不一樣的緣由引發該類變化,其實就是耦合了多個互不相關的職責,就會下降這個類的內聚性。編程
例如咱們如今有兩個類,D和C。那麼類D的對象可使用僅對類C對象有效的方法或屬性,它使得這些方法和屬性就像是由D定義的。這時,C是D的父類,D是C的子類。因爲在繼承過程當中,父類的內部細節對子類徹底可見,所以經過繼承的代碼複用被稱爲「白盒式代碼複用」(white-box reuse)。ide
所以,當你經過從另外一個對象繼承的方式來建立一個新的對象時,目標就應該是使得新的對象有一個相對於原始對象更加特定的版本。oop
一個對象能夠把對象做爲本身的成員變量,若是用這樣的類建立對象,那麼該對象中就會有其它對象,也就是說該對象將其餘對象做爲本身的組成部分(這就是人們常說的Has-A),或者說該對象是由幾個對象組合而成。this
對象組合就是經過對現有的對象進行拼裝(組合)產生新的、更復雜的功能,而因爲對象之間各自內部細節不對外可見,因此這種方式的代碼複用被稱爲「黑盒式代碼複用」(black-box reuse)。對象組合要求被組合的對象具備良好定義的接口。spa
舉例:.net
<?php class person{ public $name; public $gender; public function say(){ echo $this->name," \tis ",$this->gender,"\r\n"; } } class family{ public $people; public $location; public function construct($p,$loc){ $this->people=$p; $this->location=$loc; } } $student=new person(); $student->name='Tom'; $student->gender='male'; $student->say(); $tom=new family($student,'peking');
以上代碼中,定義了兩個類,一個是person,一個是family;在family類中建立person類中的對象,把這個對象視爲family類的一個屬性,並調用它的方法處理問題,這種複用方式就叫「組合」。設計
二、繼承與組合區別code
類繼承是在編譯時刻靜態定義的,且可直接使用,由於程序設計語言直接支持類繼承。類繼承能夠較方便地改變被複用的實現。當一個子類重定義一些而不是所有操做時,它也能影響它所繼承的操做,只要在這些操做中調用了被重定義的操做。
可是類繼承也有一些不足之處。首先,由於繼承在編譯時刻就定義了,因此沒法在運行時刻改變從父類繼承的實現。更糟的是,父類一般至少定義了部分子類的具體表示。由於繼承對子類揭示了其父類的實現細節,因此繼承常被認爲「破壞了封裝性」 。子類中的實現與它的父類有如此緊密的依賴關係,以致於父類實現中的任何變化必然會致使子類發生變化。當你須要複用子類時,實現上的依賴性就會產生一些問題。若是繼承下來的實現不適合解決新的問題,則父類必須重寫或被其餘更適合的類替換。這種依賴關係限制了靈活性並最終限制了複用性。一個可用的解決方法就是只繼承抽象類,由於抽象類一般提供較少的實現。
對象組合是經過得到對其餘對象的引用而在運行時刻動態定義的。組合要求對象遵照彼此的接口約定,進而要求更仔細地定義接口,而這些接口並不妨礙你將一個對象和其餘對象一塊兒使用。這還會產生良好的結果:由於對象只能經過接口訪問,因此咱們並不破壞封裝性;只要類型一致,運行時刻還能夠用一個對象來替代另外一個對象;更進一步,由於對象的實現是基於接口寫的,因此實現上存在較少的依賴關係。
對象組合對系統設計還有另外一個做用,即優先使用對象組合有助於你保持每一個類被封裝,並被集中在單個任務上。這樣類和類繼承層次會保持較小規模,而且不太可能增加爲不可控制的龐然大物。另外一方面,基於對象組合的設計會有更多的對象 (而有較少的類),且系統的行爲將依賴於對象間的關係而不是被定義在某個類中。
這導出了咱們的面向對象設計的第二個原則:優先使用對象組合,而不是類繼承。
推薦閱讀》》