一、引言 前兩天休息日在網上打QQ鬥地主,每盤結束後騰訊游戲平臺會自動計算輸贏的歡樂豆,嗯?挺好的,平時在面對面玩鬥地主時,一盤游戲結束後,我們需要瞭解每個人的出牌狀況,然後算出來輸贏。現在有了游戲平臺,玩家之間計算輸贏這個操作交給了游戲平臺,我們不再需要瞭解每個人的出牌狀況。在軟體設計中,我們將解 ...
一、引言
前兩天休息日在網上打QQ鬥地主,每盤結束後騰訊游戲平臺會自動計算輸贏的歡樂豆,嗯?挺好的,平時在面對面玩鬥地主時,一盤游戲結束後,我們需要瞭解每個人的出牌狀況,然後算出來輸贏。現在有了游戲平臺,玩家之間計算輸贏這個操作交給了游戲平臺,我們不再需要瞭解每個人的出牌狀況。在軟體設計中,我們將解決這種業務場景的模式稱之為中介者模式
二、中介者模式
定義:用一個中介對象來封裝一系列對象的交互。中介者使各對象不需要顯式的相互引用,從而使其耦合鬆散,而且獨立改變它們之間的交互。
下麵是中介者模式結構圖:
為什麼要使用中介者模式?
如果不使用中介者模式,各個同事對象將相互引用,如果每個對象都與多個對象交互時,將形成下圖所示網狀結構:
分析:上圖中每個對象之間過度耦合,不利於類的復用也不利於擴展。假如對象一變化了將可能引起與它直接相依賴的所有對象的調整,所以同事對象之間直接依賴不是好的設計。
如果採用中介者模式,那麼對象之間的關係將變成下圖所示星型結構;
分析:使用中介者模式後,任何一個同事對象的變化,只會影響中介者和類本身,不會像之前設計中一個對象變化,將會引用所有與之關聯的對象變化
場景:兩個人本金都是100,在一起打牌,每盤結束後計算兩個人的金額
下麵是不使用中介者模式的demo:
//抽象同事類 充當牌友類 public abstract class Colleague { public int Number { get; set; } public abstract void Win(int number, Colleague colleague); } //牌友A類 public class ConcreteColleagueA : Colleague { public override void Win(int number, Colleague colleague) { this.Number += number; colleague.Number -= number; } } //牌友B類 class ConcreteColleagueB : Colleague { public override void Win(int number, Colleague colleague) { this.Number += number; colleague.Number -= number; } } class Program { static void Main(string[] args) { //A和B兩個人打牌 Colleague colleagueA = new ConcreteColleagueA(); Colleague colleagueB = new ConcreteColleagueB(); colleagueA.Number = 100; colleagueB.Number = 100; //A贏了B就輸錢 colleagueA.Win(5, colleagueB); Console.WriteLine($"A的數量為{colleagueA.Number}"); Console.WriteLine($"B的數量為{colleagueA.Number}"); Console.Read(); } }View Code
分析:上述確實解決了場景中的問題,牌友A和牌友B都依賴於抽象,從而降低同事類之間的耦合度。這樣的設計中,牌友A的變化會引起牌友B的變化,但是如果現在要新增一個牌友C、D、E呢?設計到多個對象的變化時,當前同事類需要瞭解其他所有涉及的同事類狀況,這時就需要修改同事類了,而且,多個牌友計算輸贏時任何一個人計算錯誤,都會導致整個業務場景中的計算錯誤。基於此思考,能不能把計算的錢的任務交給程式做呢?譬如QQ鬥地主。。。即引入中介者對象來協調各個對象之間的關係
下麵是引入中介者對象的代碼demo
//抽象同事類 public abstract class Colleague { public int Number { get; set; } public abstract void Win(int number, Mediator mediator); } //抽象中介者類 public abstract class Mediator { public ConcreteColleagueA A; public ConcreteColleagueB B; public Mediator(ConcreteColleagueA a, ConcreteColleagueB b) { A = a; B = b; } public abstract void AWin(int number); public abstract void BWin(int number); } public class ConcreteColleagueA : Colleague { public override void Win(int number, Mediator mediator) { mediator.AWin(number); } } public class ConcreteColleagueB : Colleague { public override void Win(int number, Mediator mediator) { mediator.BWin(number); } } class ConcreteMediator : Mediator { public ConcreteMediator(ConcreteColleagueA a, ConcreteColleagueB b) : base(a,b) { } public override void AWin(int number) { A.Number += number; B.Number -= number; } public override void BWin(int number) { A.Number -= number; B.Number += number; } } class Program { static void Main(string[] args) { ConcreteColleagueA concreteColleagueA = new ConcreteColleagueA(); ConcreteColleagueB concreteColleagueB = new ConcreteColleagueB(); ConcreteMediator concreteMediator = new ConcreteMediator(concreteColleagueA, concreteColleagueB); concreteColleagueA.Number = 100; concreteColleagueB.Number = 100; concreteMediator.AWin(5); Console.WriteLine($"A的數量為{concreteColleagueA.Number}"); Console.WriteLine($"B的數量為{concreteColleagueB.Number}"); Console.WriteLine(); Console.Read(); } }View Code
分析:運行結果和上面不使用中介者模式的代碼運行結果一致,這樣如果某個牌友類變化時,只會影響到該變化的牌友類和中介者類,從而解決上面代碼中的問題。
但是此時如果要新增一個牌友類,我們就不得不修改抽象中介者類,還可以再完善一下嗎?完全可以,我們可以結合觀察者模式,在抽象中介者類中保存一個抽象牌友類的集合,添加保存刪除牌友的方法管理集合,然後在具體的中介者類中,修改AWin()、BWin()迴圈遍歷執行改變自己和其他牌友的錢數。此時仍然存在一個問題,新增牌友時,我們雖然不需要修改抽象中介者類,但是還是要在具體中介者類中添加CWin()方法,這時可以此採用狀態模式來解決問題,具體會在下一個專題中介紹。
下麵是大話設計模式中的例子輔助理解中介者模式:
abstract class Colleague { protected Mediator mediator; public Colleague(Mediator mediator) { this.mediator = mediator; } } abstract class Mediator { public abstract void Send(string message, Colleague colleague); } class ConcreteColleagueA : Colleague { public ConcreteColleagueA(Mediator mediator) : base(mediator) { } public void Send(string message) { mediator.Send(message, this); } public void Notify(string message) { Console.WriteLine("同事A得到消息:"+message); } } class ConcreteColleagueB : Colleague { public ConcreteColleagueB(Mediator mediator) : base(mediator) { } public void Send(string message) { mediator.Send(message, this); } public void Notify(string message) { Console.WriteLine("同事B得到消息:" + message); } } class ConcreteMediator : Mediator { private ConcreteColleagueA concreteColleagueA; private ConcreteColleagueB concreteColleagueB; public ConcreteColleagueA ConcreteColleagueA { set { concreteColleagueA = value; } } public ConcreteColleagueB ConcreteColleagueB { set { concreteColleagueB = value; } } public override void Send(string message, Colleague colleague) { if(colleague==concreteColleagueA) { concreteColleagueB.Notify(message); } else if(colleague==concreteColleagueB) { concreteColleagueA.Notify(message); } } } class Program { static void Main(string[] args) { ConcreteMediator concreteMediator = new ConcreteMediator(); ConcreteColleagueA concreteColleagueA = new ConcreteColleagueA(concreteMediator); ConcreteColleagueB concreteColleagueB = new ConcreteColleagueB(concreteMediator); concreteMediator.ConcreteColleagueA = concreteColleagueA; concreteMediator.ConcreteColleagueB = concreteColleagueB; concreteColleagueA.Send("你吃過飯了嗎?"); concreteColleagueB.Send("我吃過了"); Console.Read(); } }View Code
優點:
1.將系統各個對象之間的關係進行封裝,將各個同事類解耦,使系統松耦合
2.將對象間一對多關係轉變為一對一關聯,使對象間關係易於理解和維護
3.提高系統靈活性,使各個同事類獨立而易於復用
缺點:
1.中介者承擔的責任太重,一旦中介者出現問題,整個系統將會受到影響
2.新增加一個同事類時,不得不修改抽象中介者類和具體的中介者類
適用場景:
1.一組定義好的關係,要進行複雜的通信(如最開始對象間關係成網狀結構)時,使用中介者模式可以使同事類間關係更清晰
2.想通過一個中間類來封裝多個類中的行為
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接。
參照:
1.大話設計模式
2.http://www.cnblogs.com/zhili/p/MediatorPattern.html