什麼是中介者模式? 在現實生活中,有很多中介者模式的身影,例如QQ游戲平臺,聊天室、QQ群、簡訊平臺和房產中介。不論是QQ游戲還是QQ群,它們都是充當一個中間平臺,QQ用戶可以登錄這個中間平臺與其他QQ用戶進行交流,如果沒有這些中間平臺,我們如果想與朋友進行聊天的話,可能就需要當面才可以了。電話、短 ...
什麼是中介者模式?
在現實生活中,有很多中介者模式的身影,例如QQ游戲平臺,聊天室、QQ群、簡訊平臺和房產中介。不論是QQ游戲還是QQ群,它們都是充當一個中間平臺,QQ用戶可以登錄這個中間平臺與其他QQ用戶進行交流,如果沒有這些中間平臺,我們如果想與朋友進行聊天的話,可能就需要當面才可以了。電話、簡訊也同樣是一個中間平臺,有了這個中間平臺,每個用戶都不要直接依賴與其他用戶,只需要依賴這個中間平臺就可以了,一切操作都由中間平臺去分發。
中介者模式,定義了一個中介對象來封裝一系列對象之間的交互關係。中介者使各個對象之間不需要顯式地相互引用,從而使耦合性降低,而且可以獨立地改變它們之間的交互行為。
設計思路及代碼實現
以現實生活中打牌的例子來實現下中介者模式。打牌總有輸贏,對應的則是貨幣的變化,如果不用中介者模式的話,實現如下:
/// <summary> /// 抽象牌友類 /// </summary> public abstract class AbstractCardPartner { public int Money { get; set; } public abstract void ChangeMoney(int money, AbstractCardPartner other); } /// <summary> /// 牌友A /// </summary> public class PartnerA : AbstractCardPartner { public override void ChangeMoney(int money, AbstractCardPartner other) { Money += money; other.Money -= money; } } /// <summary> /// 牌友B /// </summary> public class PartnerB : AbstractCardPartner { public override void ChangeMoney(int money, AbstractCardPartner other) { Money += money; other.Money -= money; } } /// <summary> /// 調用 /// </summary> /// <param name="args"></param> static void Main(string[] args) { AbstractCardPartner A = new PartnerA(); A.Money = 20; AbstractCardPartner B = new PartnerB(); B.Money = 20; // A贏了B的錢減少 A.ChangeMoney(5, B); Console.WriteLine("A 現在的錢是:{0}", A.Money); // 應該是25 Console.WriteLine("B 現在的錢是:{0}", B.Money); // 應該是15 // B贏了A的錢減少 B.ChangeMoney(10, A); Console.WriteLine("A 現在的錢是:{0}", A.Money); // 應該是15 Console.WriteLine("B 現在的錢是:{0}", B.Money); // 應該是25 Console.ReadLine(); }
這樣的實現確實解決了上面場景中的問題,並且使用了抽象類使具體牌友A和牌友B都依賴於抽象類,從而降低了同事類之間的耦合度。但是如果其中牌友A發生變化時,此時就會影響到牌友B的狀態,如果涉及的對象變多的話,這時候某一個牌友的變化將會影響到其他所有相關聯的牌友狀態。例如牌友A算錯了錢,這時候牌友A和牌友B的錢數都不正確了,如果是多個人打牌的話,影響的對象就會更多。這時候就會思考——能不能把算錢的任務交給程式或者算數好的人去計算呢,這時候就有了我們QQ游戲中的歡樂鬥地主等牌類游戲了。
進一步完善的方案,即加入一個中介者對象來協調各個對象之間的關聯,這也就是中介者模式的應用了,具體完善後的實現代碼如下所示:
/// <summary> /// 抽象牌友類 /// </summary> public abstract class AbstractCardPartner { public int Money { get; set; } public abstract void ChangeMoney(int money, AbstractMediator mediator); } /// <summary> /// 牌友A /// </summary> public class PartnerA : AbstractCardPartner { public override void ChangeMoney(int money, AbstractMediator mediator) { mediator.AWin(money); } } /// <summary> /// 牌友B /// </summary> public class PartnerB : AbstractCardPartner { public override void ChangeMoney(int money, AbstractMediator mediator) { mediator.BWin(money); } } /// <summary> /// 抽象中介者類 /// </summary> public abstract class AbstractMediator { protected AbstractCardPartner A; protected AbstractCardPartner B; public AbstractMediator(AbstractCardPartner a, AbstractCardPartner b) { A = a; B = b; } public abstract void AWin(int money); public abstract void BWin(int money); } /// <summary> /// 調用 /// </summary> /// <param name="args"></param> static void Main(string[] args) { AbstractCardPartner A = new PartnerA(); AbstractCardPartner B = new PartnerB(); A.Money = 20; B.Money = 20; AbstractMediator mediator = new MediatorPater(A, B); // A贏了 A.ChangeMoney(5, mediator); Console.WriteLine("A 現在的錢是:{0}", A.Money); // 應該是25 Console.WriteLine("B 現在的錢是:{0}", B.Money); // 應該是15 // B贏了 B.ChangeMoney(10, mediator); Console.WriteLine("A 現在的錢是:{0}", A.Money); // 應該是15 Console.WriteLine("B 現在的錢是:{0}", B.Money); // 應該是25 Console.ReadLine(); }
在上面的實現代碼中,抽象中介者類保存了兩個抽象牌友類,如果新添加一個牌友類似時,此時就不得不去更改這個抽象中介者類。可以結合觀察者模式來解決這個問題,即抽象中介者對象保存抽象牌友的類別,然後添加Register和UnRegister方法來對該列表進行管理,然後在具體中介者類中修改AWin和BWin方法,遍歷列表,改變自己和其他牌友的錢數。這樣的設計還是存在一個問題——即增加一個新牌友時,此時雖然解決了抽象中介者類不需要修改的問題,但此時還是不得不去修改具體中介者類,即添加CWin方法,我們可以採用狀態模式來解決這個問題,關於狀態模式的介紹將會在下一篇進行介紹。
中介者模式的優缺點
優點:
- 簡化了對象之間的關係,將系統的各個對象之間的相互關係進行封裝,將各個同事類解耦,使得系統變為松耦合。
- 提供系統的靈活性,使得各個同事對象獨立而易於復用。
缺點:
- 中介者模式中,中介者角色承擔了較多的責任,所以一旦這個中介者對象出現了問題,整個系統將會受到重大的影響。
- 新增加一個同事類時,不得不去修改抽象中介者類和具體中介者類,此時可以使用觀察者模式和狀態模式來解決這個問題。
中介者模式的適用場景
以下情況下可以考慮使用中介者模式:
- 一組定義良好的對象,現在要進行複雜的相互通信。
- 想通過一個中間類來封裝多個類中的行為,而又不想生成太多的子類。