用一个中介对象来封装一系列对象的交互。中介者使各个对象不需要显示的相互引用,从而使其耦合松散,而且可以独立的改变他们之间的交互。
适用性:
- 一组对象以定义良好但是以复杂的方式进行通信,产生的相互依赖关系结构混乱且难以理解。
- 一个对象引用其他很多对象并且直接与这些对象通信,使这些对象难以复用。
- 想定制一个分布在多个类中的行为,而又不想生成太多的子类。
参与者:
Mediator
——中介者定义一个接口,用于与各同事对象通信
ConcreteMediator
——具体中介者可以通过协调各个同事对象实现协作行为
——了解并维护它的各个同事
Colleague Class
——每一个同事类都知道它的中介者对象
——每一个同事对象在需要与其他同事通信的时候,与它的中介者通信
在现实生活中,两个人打牌,如果某个人赢了都会影响到对方状态的改变。如果此时不采用中介者模式实现的话,则上面的场景的实现如下所示:
1 // 抽象牌友类 2 public abstract class AbstractCardPartner 3 { 4 public int MoneyCount { get; set; } 5 6 public AbstractCardPartner() 7 { 8 MoneyCount = 0; 9 } 10 11 public abstract void ChangeCount(int Count, AbstractCardPartner other); 12 }
1 // 牌友A类 2 public class ParterA : AbstractCardPartner 3 { 4 public override void ChangeCount(int Count, AbstractCardPartner other) 5 { 6 this.MoneyCount += Count; 7 other.MoneyCount -= Count; 8 } 9 }
1 // 牌友B类 2 public class ParterB : AbstractCardPartner 3 { 4 public override void ChangeCount(int Count, AbstractCardPartner other) 5 { 6 this.MoneyCount += Count; 7 other.MoneyCount -= Count; 8 } 9 }
1 class Program 2 { 3 // A,B两个人打牌 4 static void Main(string[] args) 5 { 6 AbstractCardPartner A = new ParterA(); 7 A.MoneyCount = 20; 8 AbstractCardPartner B = new ParterB(); 9 B.MoneyCount = 20; 10 11 // A 赢了则B的钱就减少 12 A.ChangeCount(5, B); 13 Console.WriteLine("A 现在的钱是:{0}", A.MoneyCount);// 应该是25 14 Console.WriteLine("B 现在的钱是:{0}", B.MoneyCount); // 应该是15 15 16 // B赢了A的钱也减少 17 B.ChangeCount(10, A); 18 Console.WriteLine("A 现在的钱是:{0}", A.MoneyCount); // 应该是15 19 Console.WriteLine("B 现在的钱是:{0}", B.MoneyCount); // 应该是25 20 Console.Read(); 21 } 22 }
上面确实完美解决了上面场景中的问题,并且使用了抽象类使具体牌友A和牌友B都依赖于抽象类,从而降低了同事类之间的耦合度。但是这样的设计,如果其中牌友A发生变化时,此时就会影响到牌友B的状态,如果涉及的对象变多的话,这时候某一个牌友的变化将会影响到其他所有相关联的牌友状态。例如牌友A算错了钱,这时候牌友A和牌友B的钱数都不正确了,如果是多个人打牌的话,影响的对象就会更多。这时候就会思考——能不能把算钱的任务交给程序或者算数好的人去计算呢,这时候就有了我们QQ游戏中的欢乐斗地主等牌类游戏了。所以上面的设计,我们还是有进一步完善的方案的,即加入一个中介者对象来协调各个对象之间的关联,这也就是中介者模式的应用了,具体完善后的实现代码如下所示:
1 // 抽象牌友类 2 public abstract class AbstractCardPartner 3 { 4 public int MoneyCount { get; set; } 5 6 public AbstractCardPartner() 7 { 8 MoneyCount = 0; 9 } 10 11 public abstract void ChangeCount(int Count, AbstractMediator mediator); 12 }
// 牌友A类 public class ParterA : AbstractCardPartner { // 依赖与抽象中介者对象 public override void ChangeCount(int Count, AbstractMediator mediator) { mediator.AWin(Count); } }
1 // 牌友B类 2 public class ParterB : AbstractCardPartner 3 { 4 // 依赖与抽象中介者对象 5 public override void ChangeCount(int Count, AbstractMediator mediator) 6 { 7 mediator.BWin(Count); 8 } 9 }
1 // 抽象中介者类 2 public abstract class AbstractMediator 3 { 4 protected AbstractCardPartner A; 5 protected AbstractCardPartner B; 6 public AbstractMediator(AbstractCardPartner a, AbstractCardPartner b) 7 { 8 A = a; 9 B = b; 10 } 11 12 public abstract void AWin(int count); 13 public abstract void BWin(int count); 14 }
1 // 具体中介者类 2 public class MediatorPater : AbstractMediator 3 { 4 public MediatorPater(AbstractCardPartner a, AbstractCardPartner b) 5 : base(a, b) 6 { 7 } 8 9 public override void AWin(int count) 10 { 11 A.MoneyCount += count; 12 B.MoneyCount -= count; 13 } 14 15 public override void BWin(int count) 16 { 17 B.MoneyCount += count; 18 A.MoneyCount -= count; 19 } 20 }
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 AbstractCardPartner A = new ParterA(); 6 AbstractCardPartner B = new ParterB(); 7 // 初始钱 8 A.MoneyCount = 20; 9 B.MoneyCount = 20; 10 11 AbstractMediator mediator = new MediatorPater(A, B); 12 13 // A赢了 14 A.ChangeCount(5, mediator); 15 Console.WriteLine("A 现在的钱是:{0}", A.MoneyCount);// 应该是25 16 Console.WriteLine("B 现在的钱是:{0}", B.MoneyCount); // 应该是15 17 18 // B 赢了 19 B.ChangeCount(10, mediator); 20 Console.WriteLine("A 现在的钱是:{0}", A.MoneyCount);// 应该是15 21 Console.WriteLine("B 现在的钱是:{0}", B.MoneyCount); // 应该是25 22 Console.Read(); 23 } 24 } 25 }
从上面实现代码可以看出,此时牌友A和牌友B都依赖于抽象的中介者类,这样如果其中某个牌友类变化只会影响到,只会影响到该变化牌友类本身和中介者类,从而解决前面实现代码出现的问题,具体的运行结果和前面实现结果一样。
在上面的实现代码中,抽象中介者类保存了两个抽象牌友类,如果新添加一个牌友类似时,此时就不得不去更改这个抽象中介者类。可以结合观察者模式来解决这个问题,即抽象中介者对象保存抽象牌友的类别,然后添加Register和UnRegister方法来对该列表进行管理,然后在具体中介者类中修改AWin和BWin方法,遍历列表,改变自己和其他牌友的钱数。这样的设计还是存在一个问题——即增加一个新牌友时,此时虽然解决了抽象中介者类不需要修改的问题,但此时还是不得不去修改具体中介者类,即添加CWin方法,我们可以采用状态模式来解决这个问题。
中介者模式,定义了一个中介对象来封装系列对象之间的交互。中介者使各个对象不需要显式地相互引用,从而使其耦合性降低,而且可以独立地改变它们之间的交互。中介者模式一般应用于一组定义良好的对象之间需要进行通信的场合以及想定制一个分布在多个类中的行为,而又不想生成太多的子类的情形下。
学习于 http://www.cnblogs.com/zhili/p/MediatorPattern.html