合成/聚合複用原則(CARP),儘可能使用合成/聚合,儘可能不要使用類繼承。javascript
合成和聚合都是關聯的特殊種類。聚合表示一種弱的「擁有關係」,體現的是A對象能夠包含B對象,但B對象不必定是A對象的一部分;合成則是一種槍的‘擁有’關係,體現了嚴格的部分和總體的關係,部分和總體的聲明週期同樣。比方說,大雁有兩個翅膀,翅膀與大雁是部分和總體的關係,而且它們的聲明週期是相同的,因而大雁和翅膀就是合成關係。而大雁是羣居動物,因此每隻大雁都是屬於一個雁羣,一個雁羣能夠有多隻大雁,因此大雁和雁羣是聚合關係。html
合成/聚合複用原則的好處是,有限使用對象的合成/聚合將有助於你保持每一個類被封裝,並被集中在單個任務上。這樣類和類繼承層次會保持較小規模,而且不太可能增加爲不可控制的龐然大物。java
橋接模式(Bridge),將抽象部分與它的實現部分分離,使它們均可以獨立地變化。git
什麼叫抽象與它的實現分離,這並非說,讓抽象類與其派生類分離,由於這沒有任何意義。實現指的是抽象類和它的派生類用來實現本身的對象。橋接模式主要講的是儘可能用聚合,而不要盲目使用繼承。設計模式
下面給出橋接模式的UML圖:ide
橋接模式的基本代碼結構:post
namespace ConsoleApplication1 { abstract class Implementor { public abstract void Operation(); } class ConcreteImplementorA : Implementor { public override void Operation() { Console.WriteLine("具體實現A的方法執行"); } } class ConcreteImplementorB : Implementor { public override void Operation() { Console.WriteLine("具體實現B的方法執行"); } } class Abstraction { protected Implementor implementor; public void SetImplementor(Implementor implementor) { this.implementor = implementor; } public virtual void Operation() { implementor.Operation(); } } class RefinedAbstraction : Abstraction { public override void Operation() { implementor.Operation(); } } class Program { static void Main(string[] args) { Abstraction ab = new RefinedAbstraction(); ab.SetImplementor(new ConcreteImplementorA()); ab.Operation(); ab.SetImplementor(new ConcreteImplementorB()); ab.Operation(); Console.ReadKey(); } } }
結果:學習
實現系統可能有多角度分類,每一種分那麼類都有可能變化,那麼就把這種多角度分離出來讓它們獨立變化,減小它們之間的耦合。this
其實只要真正瞭解設計原則,不少設計模式其實就是原則的應用而已,或許在不知不覺中就在使用設計模式了。spa
如今回到《大話設計模式》中的手機品牌與軟件的例子
namespace ConsoleApplication1 { //手機軟件抽象類 abstract class HandsetSoft { public abstract void Run(); } //手機遊戲 class HandsetGame : HandsetSoft { public override void Run() { Console.WriteLine("運行手機遊戲"); } } //手機通信錄 class HandsetAddressList : HandsetSoft { public override void Run() { Console.WriteLine("運行和蒐集通信錄"); } } //手機品牌抽象類 abstract class HandsetBrand { protected HandsetSoft soft; //設置手機軟件 public void SetHandsetSoft(HandsetSoft soft) //品牌須要關注軟件,因此可在機器中安裝軟件(設置手機軟件),以備運行 { this.soft = soft; } //運行 public abstract void Run(); } //手機品牌N class HandsetBrandN : HandsetBrand { public override void Run() { soft.Run(); } } //手機品牌M class HandsetBrandM : HandsetBrand { public override void Run() { soft.Run(); } } class Program { static void Main(string[] args) { HandsetBrand ab; ab = new HandsetBrandN(); ab.SetHandsetSoft(new HandsetGame()); ab.Run(); ab.SetHandsetSoft(new HandsetAddressList()); ab.Run(); ab = new HandsetBrandM(); ab.SetHandsetSoft(new HandsetGame()); ab.Run(); ab.SetHandsetSoft(new HandsetAddressList()); ab.Run(); Console.ReadKey(); } } }
這樣寫的好處很是好,若是如今要增長一個功能,例如MP3音樂播放功能,那麼只要增長一個MP3音樂播放類就能夠了。
在《大話設計模式》中有一個用繼承的寫法,如今放上它的類圖:
在這種用繼承的方法,就增長一個MP3音樂播放功能,那就須要在每一個品牌下添加一個MP3音樂播放類,若是須要再添加一個手機品牌,也有通信錄,遊戲,MP3播放器功能,那就須要添加至關多的類,崩潰。
可是上面的橋接模式的類圖:
手機品牌與手機軟件之間是聚合關係,當須要添加一個MP3音樂播放功能時,只須要添加一個類,而須要添加一個手機品牌時,也只是須要添加一個類。