C#設計模式(16)——中介者模式

撈月亮的猴子發表於2018-12-10

1.中介者模式介紹

  中介者模式,定義了一箇中介物件來封裝一系列物件之間的互動關係,中介者使各個物件之間不需要顯式地相互引用,從而降低耦合性。在開發中我們會遇到各個物件相互引用的情況,每個物件都可以和多個物件進行互動,這時將會形成複雜的一對多結構的網狀結構,各個物件之間過度耦合,這樣不利於類的複用和擴充套件。如果引入了中介者模式,各個物件都通過中介者進行互動,那麼物件之間的關係將變成一對一的星型結構。

 

  我們採用園友LearningHard玩牌的例子來理解中介者模式的用法。在現實生活中,兩個人打牌,如果某個人贏了會影響到對方的狀態。標準中介者模式有抽象中介者角色,具體中介者角色、抽象同事類和具體同事類四個角色,其中打牌的人都是具體的同事類的物件,算賬的平臺是中介者物件。如果此時不採用中介者模式實現的話,則程式碼實現打牌的場景如下所示:

    //抽象玩家類
    public abstract class AbstractCardPlayer
    {
        public int MoneyCount { get; set; }
        public AbstractCardPlayer()
        {
            this.MoneyCount = 0;
        }
        public abstract void ChangeCount(int count, AbstractCardPlayer other);
    }
//玩家A類 public class PlayerA : AbstractCardPlayer { public override void ChangeCount(int count, AbstractCardPlayer other) { this.MoneyCount += count; other.MoneyCount -= count; } }
//玩家B類 public class PlayerB : AbstractCardPlayer { public override void ChangeCount(int count, AbstractCardPlayer other) { this.MoneyCount += count; other.MoneyCount -= count; } }

class Program { static void Main(string[] args) { AbstractCardPlayer a = new PlayerA() { MoneyCount = 20 }; AbstractCardPlayer b = new PlayerB() { MoneyCount = 20 }; //玩家a贏了玩家b 5元 Console.WriteLine("a贏了b5元"); a.ChangeCount(5, b); Console.WriteLine($"玩家a現在有{a.MoneyCount}元"); Console.WriteLine($"玩家b現在有{b.MoneyCount}元"); //玩家b贏了玩家a 10元 Console.WriteLine("b贏了a10元"); b.ChangeCount(10, a); Console.WriteLine($"玩家a現在有{a.MoneyCount}元"); Console.WriteLine($"玩家b現在有{b.MoneyCount}元"); Console.ReadKey(); } }

執行結果如下:

  上邊的程式碼滿足了玩牌的功能,但是有一些缺陷:我們看到上邊栗子中算錢的功能是交給贏家的a.ChangeCount(count, b)方法來實現的,這時是贏家找輸家要錢 贏家a和輸家b是直接通訊的。當玩家比較多的時候,例如a贏了,bcde四個玩家都會輸5元,那麼a就要和bcde玩家都要通訊(多玩家方法改成:a.ChangeCount(count,b,c,d,e)),如b贏了同理,各個玩家組成了一個複雜的通訊網路,就像上邊的網狀圖,各個玩家過度耦合。如果我們引入一箇中間人來負責統一結算,贏家就可以直接找中間人結算,不必直接找所有的輸家要賬了,程式碼如下:

   //抽象玩家類
    public abstract class AbstractCardPlayer
    {
        public int MoneyCount { get; set; }
        public AbstractCardPlayer()
        {
            this.MoneyCount = 0;
        }
        public abstract void ChangeCount(int count, AbstractMediator mediator);
    }
    //玩家A類
    public class PlayerA : AbstractCardPlayer
    {
        //通過中介者來算賬,不用直接找輸家了
        public override void ChangeCount(int count, AbstractMediator mediator)
        {
            mediator.AWin(count);
        }
    }
    //玩家B類
    public class PlayerB : AbstractCardPlayer
    {
        public override void ChangeCount(int count, AbstractMediator mediator)
        {
            mediator.BWin(count);
        }
    }
    //抽象中介者
    public abstract class AbstractMediator
    {
        //中介者必須知道所有同事
        public AbstractCardPlayer A;
        public AbstractCardPlayer B;
        public AbstractMediator(AbstractCardPlayer a,AbstractCardPlayer b)
        {
            A = a;
            B = b;
        }
        public abstract void AWin(int count);
        public abstract void BWin(int count);
    }
    //具體中介者
    public class Mediator : AbstractMediator
    {
        public Mediator(AbstractCardPlayer a,AbstractCardPlayer b):base(a,b){}
        public override void AWin(int count)
        {
            A.MoneyCount += count;
            B.MoneyCount -= count;
        }
        public override void BWin(int count)
        {
            A.MoneyCount -= count;
            B.MoneyCount += count;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            AbstractCardPlayer a = new PlayerA() { MoneyCount = 20 };
            AbstractCardPlayer b = new PlayerB() { MoneyCount = 20 };
            AbstractMediator mediator = new Mediator(a, b);
            //玩家a贏了玩家b 5元
            Console.WriteLine("a贏了b5元");
            a.ChangeCount(5, mediator);
            Console.WriteLine($"玩家a現在有{a.MoneyCount}元");
            Console.WriteLine($"玩家b現在有{b.MoneyCount}元");
            //玩家b贏了玩家a 10元
            Console.WriteLine("b贏了a10元");
            b.ChangeCount(10, mediator);
            Console.WriteLine($"玩家a現在有{a.MoneyCount}元");
            Console.WriteLine($"玩家b現在有{b.MoneyCount}元");
            Console.ReadKey();
        }
    }

  執行結果和不用中介者的例子一致。我們可以看到中介者模式降低了各個同事物件的耦合,同事類之間不用直接通訊,直接找中介者就行了,但是中介者模式並沒有降低業務的複雜度,中介者將同事類間的複雜互動邏輯從業務程式碼中轉移到了中介者類的內部。標準中介者模式有抽象中介者角色,具體中介者角色、抽象同事類和具體同事類四個角色,在實際開發中有時候沒必要對具體中介者角色和具體使用者角色進行抽象(如聯合國作為一箇中介者,負責調停各個國家糾紛,但是沒必要把單獨的聯合國抽象成一個抽象中介者類;上邊例子的抽象玩家類和抽象中介者類都是沒必要的),我們可以根據具體的情況來來選擇是否使用抽象中介者和抽象使用者角色。

2.小結

1.上邊例子的類圖

中介者模式優點:

  1 降低了同事類互動的複雜度,將一對多轉化成了一對一;

  2 各個類之間的解耦;

  3 符合迪米特原則。

中介者模式缺點:

  1 業務複雜時中介者類會變得複雜難以維護。

 

參考文獻

 [1] http://www.runoob.com/design-pattern/mediator-pattern.html

 [2] http://www.cnblogs.com/zhili/p/MediatorPattern.html

 

相關文章