C#设计模式(16)——中介者模式
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