什么是中介者模式?
在現實生活中,有很多中介者模式的身影,例如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方法,我們可以采用狀態模式來解決這個問題,關於狀態模式的介紹將會在下一篇進行介紹。
中介者模式的優缺點
優點:
- 簡化了對象之間的關系,將系統的各個對象之間的相互關系進行封裝,將各個同事類解耦,使得系統變為松耦合。
- 提供系統的靈活性,使得各個同事對象獨立而易於復用。
缺點:
- 中介者模式中,中介者角色承擔了較多的責任,所以一旦這個中介者對象出現了問題,整個系統將會受到重大的影響。
- 新增加一個同事類時,不得不去修改抽象中介者類和具體中介者類,此時可以使用觀察者模式和狀態模式來解決這個問題。
中介者模式的適用場景
以下情況下可以考慮使用中介者模式:
- 一組定義良好的對象,現在要進行復雜的相互通信。
- 想通過一個中間類來封裝多個類中的行為,而又不想生成太多的子類。



