• 设计模式-行为型-中介者模式


    中介者模式(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

  • 相关阅读:
    《P3953 [NOIP2017 提高组] 逛公园》
    《P4180 [BJWC2010]严格次小生成树》
    《济南icpc补题》
    《levil的因子和》
    《洛谷P2704 [NOI2001]炮兵阵地》
    《Codeforces Round #689 (Div. 2, based on Zed Code Competition)》
    《2174: Leapin' Lizards》
    《3820: Revenge of Fibonacci 》
    马拉车求最长回文子串
    二分训练
  • 原文地址:https://www.cnblogs.com/az4215/p/11639279.html
Copyright © 2020-2023  润新知