中介者模式(Mediator): 在現實生活中,有很多中介者模式的身影,例如QQ游戲平臺,聊天室、QQ群、簡訊平臺和房產中介。不論是QQ游戲還是QQ群,它們都是充當一個中間平臺,QQ用戶可以登錄這個中間平臺與其他QQ用戶進行交流,如果沒有這些中間平臺,我們如果想與朋友進行聊天的話,可能就需要當面才可 ...
中介者模式(Mediator):
在現實生活中,有很多中介者模式的身影,例如QQ游戲平臺,聊天室、QQ群、簡訊平臺和房產中介。不論是QQ游戲還是QQ群,它們都是充當一個中間平臺,QQ用戶可以登錄這個中間平臺與其他QQ用戶進行交流,如果沒有這些中間平臺,我們如果想與朋友進行聊天的話,可能就需要當面才可以了。電話、簡訊也同樣是一個中間平臺,有了這個中間平臺,每個用戶都不要直接依賴與其他用戶,只需要依賴這個中間平臺就可以了,一切操作都由中間平臺去分發。中介者模式,定義了一個中介對象來封裝一系列對象之間的交互關係。中介者使各個對象之間不需要顯式地相互引用,從而使耦合性降低,而且可以獨立地改變它們之間的交互行為。
中介者模式的角色:
1)抽象中介者(Mediator):定義了同事對象到中介者對象的介面。
2)具體中介者(ConcreteMediator):實現抽象類的方法,它需要知道具體的同事類並從具體同事類接受消息,向具體同事對象發出命令。
3)抽象同事類(Colleague):定義同事類的介面,保存中介者對象,提供同事對象交互的抽象方法,實現所有相互影響的同事類的公共功能。
4)具體同事類(ConcreteColleague):每個具體同事類只知道自己的行為,而不瞭解其他同事類的情況,但它們認識中介者對象。
示例:
以現實生活中打牌為例,若不使用中介者模式。
1 /// <summary> 2 /// 抽象牌友類 3 /// </summary> 4 public abstract class AbstractCardPartner 5 { 6 public int Money { get; set; } 7 8 public abstract void ChangeMoney(int money, AbstractCardPartner other); 9 } 10 11 /// <summary> 12 /// 牌友A 13 /// </summary> 14 public class PartnerA : AbstractCardPartner 15 { 16 public override void ChangeMoney(int money, AbstractCardPartner other) 17 { 18 Money += money; 19 other.Money -= money; 20 } 21 } 22 23 /// <summary> 24 /// 牌友B 25 /// </summary> 26 public class PartnerB : AbstractCardPartner 27 { 28 public override void ChangeMoney(int money, AbstractCardPartner other) 29 { 30 Money += money; 31 other.Money -= money; 32 } 33 } 34 35 internal class Program 36 { 37 private static void Main(string[] args) 38 { 39 AbstractCardPartner A = new PartnerA(); 40 A.Money = 20; 41 AbstractCardPartner B = new PartnerB(); 42 B.Money = 20; 43 44 // A贏了B的錢減少 45 A.ChangeMoney(5, B); 46 Console.WriteLine("A 現在的錢是:{0}", A.Money); // 應該是25 47 Console.WriteLine("B 現在的錢是:{0}", B.Money); // 應該是15 48 49 // B贏了A的錢減少 50 B.ChangeMoney(10, A); 51 Console.WriteLine("A 現在的錢是:{0}", A.Money); // 應該是15 52 Console.WriteLine("B 現在的錢是:{0}", B.Money); // 應該是25 53 } 54 }
這樣的實現確實解決了上面場景中的問題,並且使用了抽象類使具體牌友A和牌友B都依賴於抽象類,從而降低了同事類之間的耦合度。但是如果其中牌友A發生變化時,此時就會影響到牌友B的狀態,如果涉及的對象變多的話,這時候某一個牌友的變化將會影響到其他所有相關聯的牌友狀態。例如牌友A算錯了錢,這時候牌友A和牌友B的錢數都不正確了,如果是多個人打牌的話,影響的對象就會更多。這時候就會思考——能不能把算錢的任務交給程式或者算數好的人去計算呢,這時候就有了我們QQ游戲中的歡樂鬥地主等牌類游戲了。
1 /// <summary> 2 /// 抽象牌友類 3 /// </summary> 4 public abstract class AbstractCardPartner 5 { 6 protected AbstractMediator mediator; 7 8 public int Money { get; set; } 9 10 public abstract void Change(int money, AbstractMediator mediator); 11 } 12 13 /// <summary> 14 /// 牌友A 15 /// </summary> 16 public class PartnerA : AbstractCardPartner 17 { 18 public PartnerA(int money) 19 { 20 Money = money; 21 } 22 23 public override void Change(int money, AbstractMediator mediator) 24 { 25 Console.WriteLine($"{nameof(PartnerA)}贏了"); 26 mediator.Change(money, this); 27 } 28 } 29 30 /// <summary> 31 /// 牌友B 32 /// </summary> 33 public class PartnerB : AbstractCardPartner 34 { 35 public PartnerB(int money) 36 { 37 Money = money; 38 } 39 40 public override void Change(int money, AbstractMediator mediator) 41 { 42 Console.WriteLine($"{nameof(PartnerB)}贏了"); 43 mediator.Change(money, this); 44 } 45 } 46 47 /// <summary> 48 /// 牌友B 49 /// </summary> 50 public class PartnerC : AbstractCardPartner 51 { 52 public PartnerC(int money) 53 { 54 Money = money; 55 } 56 57 public override void Change(int money, AbstractMediator mediator) 58 { 59 Console.WriteLine($"{nameof(PartnerC)}贏了"); 60 mediator.Change(money, this); 61 } 62 } 63 64 /// <summary> 65 /// 抽象中介者類 66 /// </summary> 67 public abstract class AbstractMediator 68 { 69 public abstract void Register(AbstractCardPartner cardPartner); 70 71 // cardPartner贏錢 72 public abstract void Change(int money, AbstractCardPartner cardPartner); 73 } 74 75 public class Mediator : AbstractMediator 76 { 77 private List<AbstractCardPartner> list = new List<AbstractCardPartner>(); 78 79 public override void Register(AbstractCardPartner cardPartner) 80 { 81 list.Add(cardPartner); 82 } 83 84 public override void Change(int money, AbstractCardPartner cardPartner) 85 { 86 foreach (var item in list) 87 { 88 if (item != cardPartner) 89 { 90 cardPartner.Money += money; 91 item.Money -= money; 92 } 93 } 94 } 95 } 96 97 internal class Program 98 { 99 private static void Main(string[] args) 100 { 101 AbstractMediator mediator = new Mediator(); 102 AbstractCardPartner A = new PartnerA(20); 103 AbstractCardPartner B = new PartnerB(20); 104 AbstractCardPartner C = new PartnerC(20); 105 106 mediator.Register(A); 107 mediator.Register(B); 108 mediator.Register(C); 109 110 // A贏了 111 A.Change(5, mediator); 112 Console.WriteLine("A 現在的錢是:{0}", A.Money); // 應該是30 113 Console.WriteLine("B 現在的錢是:{0}", B.Money); // 應該是15 114 Console.WriteLine("C 現在的錢是:{0}", C.Money); // 應該是15 115 } 116 }
在上面的實現代碼中,抽象中介者類保存了兩個抽象牌友類,如果新添加一個牌友類似時,此時就不得不去更改這個抽象中介者類。可以結合觀察者模式來解決這個問題,即抽象中介者對象保存抽象牌友的類別,然後添加Register和UnRegister方法來對該列表進行管理,然後在具體中介者類中修改AWin和BWin方法,遍歷列表,改變自己和其他牌友的錢數。這樣的設計還是存在一個問題——即增加一個新牌友時,此時雖然解決了抽象中介者類不需要修改的問題,但此時還是不得不去修改具體中介者類,即添加CWin方法,我們可以採用狀態模式來解決這個問題。
在寫中介者模式的時候,我發現我將其寫成了觀察者模式,後來仔細研究發現兩者還是有區別的:
中介者模式主要是起到一個協調的作用,它知道所有的同事類且同事類含有中介者對象,即我有事通知你,你幫我協調一下。
而觀察者模式側重在當一個對象的狀態發生變化時,能夠自動通知其他關聯對象,自動刷新對象狀態。
中介者模式的優缺點:
優點:
1)簡化了對象之間的關係,將系統的各個對象之間的相互關係進行封裝,將各個同事類解耦,使得系統變為松耦合。
2)提供系統的靈活性,使得各個同事對象獨立而易於復用。
缺點:
1)中介者模式中,中介者角色承擔了較多的責任,所以一旦這個中介者對象出現了問題,整個系統將會受到重大的影響。
2)新增加一個同事類時,不得不去修改抽象中介者類和具體中介者類,此時可以使用觀察者模式和狀態模式來解決這個問題。
中介者使用的場景:
1)一組定義良好的對象,現在要進行複雜的相互通信。
2)想通過一個中間類來封裝多個類中的行為,而又不想生成太多的子類。
參考:https://www.runoob.com/design-pattern/mediator-pattern.html