設計模式之中介者模式


什么是中介者模式?

在現實生活中,有很多中介者模式的身影,例如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方法,我們可以采用狀態模式來解決這個問題,關於狀態模式的介紹將會在下一篇進行介紹。

中介者模式的優缺點

優點:

  • 簡化了對象之間的關系,將系統的各個對象之間的相互關系進行封裝,將各個同事類解耦,使得系統變為松耦合。
  • 提供系統的靈活性,使得各個同事對象獨立而易於復用。

缺點:

  • 中介者模式中,中介者角色承擔了較多的責任,所以一旦這個中介者對象出現了問題,整個系統將會受到重大的影響。
  • 新增加一個同事類時,不得不去修改抽象中介者類和具體中介者類,此時可以使用觀察者模式和狀態模式來解決這個問題。

中介者模式的適用場景

以下情況下可以考慮使用中介者模式:

  • 一組定義良好的對象,現在要進行復雜的相互通信。
  • 想通過一個中間類來封裝多個類中的行為,而又不想生成太多的子類。

代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM