动机(Motivation)
在软件构建过程中,经常会出现多个对象相互关联交互的情况,对象之间常常会维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将面临不断的变化。
在这种情况下,我们可以使用一个“中介对象”来管理对象间的关联关系,避免相互交互的对象之间的紧耦合引用,从而更好地抵御变化。
意图(Intent)
用一个中介对象来封装一系列的对象交互。中介者使各个对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
结构(Structure)
其中,
Mediator抽象中介者:定义了同事对象到中介者对象的接口。
ConcreteMediator具体中介者对象:实现抽象类的方法,它需要知道所有具体同事类,并从具体同事类接收消息,向具体同事类对象发出命令
Colleague抽象同事类:所有具体同事类的抽象接口
ConcreteColleague具体同事类:每个具体同事只知道自己的行为,而不了解其他同事类的情况,但它们却都认识中介者对象。
Mediator模式的几个要点
1.将多个对象间复杂的关联关系解耦,Mediator模式将多个对象间的控制逻辑进行集中管理,变“多个对象互相关联”为“多个对象和一个中介者关联”,简化了系统的维护,抵御了可能的变化。
2.随着控制逻辑的复杂化,Mediator具体对象的实现可能相当复杂。这时候可以对Mediator对象进行分解处理。
3.Facade模式是解耦系统外到系统内(单向)的对象关联关系;Mediator模式是解耦系统内各个对象之间(双向)的关联关系。
代码实现
实例背景
世界各个国家有着错综复杂的利益关系,政治,经济,文化,军事,外交,相互交织,相互联系。
国与国之间除了合作和平,还会存在很多冲突,在联合国组织出现之前,就爆发了二战。从联合国成立以后,就没有发生类似的大范围的战争,联合国对世界和平的贡献不可估量。在这里,联合国就扮演了一个中介者的角色,负责国与国之间的调停。
下面以美国和伊拉克通过联合国对话作为中介举例。在这个实例当中,联合国是Mediator抽象中介者,安理会是ConcreteMediator,国家是Colleague抽象同事类,美国和伊拉克是ConcreteColleague具体同事类。
联合国机构:Mediator抽象中介者,定义了同事对象到中介者对象的接口,里面有一个抽象方法用来得到同事对象和发送消息
abstract class UnitedNstions
{
//声明
public abstract void Declare(string message, Country colleague);
}
国家类:Colleague类,所有具体同事类的抽象接口(美国和伊拉克的抽象接口),里面的构造方法用来得到中介者对象
abstract class Country
{
protected UnitedNstions mediator;
public Country(UnitedNstions mediator)
{
this.mediator = mediator;
}
}
美国类和伊拉克类:ConcreteColleague类,美国和伊拉克类只知道自己,互相并不了解,但它们都知道Meidator,声明消息时通常是中介者发送出去的
class USA : Country
{
public USA(UnitedNstions mediator) : base(mediator) { }
//声明
public void Declare(string message)
{
mediator.Declare(message, this);
}
//获得消息
public void GetMessage(string message)
{
Console.WriteLine("美国获得对方消息:"+message);
}
}
class Iraq : Country
{
//代码同美国类
}
联合国安理会:具体ConcreteMediator类,联合国安理会了解所有的国家,拥有美国和伊拉克的对象属性,并且重写了Mediator类的“声明”方法,实现了两个对象间的通信
class UnitedNationsSecurityCouncil : UnitedNstions
{
private USA colleague1;
private Iraq colleague2;
//美国
public USA Colleague1
{
set { colleague1 = value; }
}
//伊拉克
public Iraq Colleague2
{
set { colleague2 = value; }
}
//声明
public override void Declare(string message, Country colleague)
{
//重写了“声明”方法,实现了两个对象间的通信
if (colleague==colleague1)
{
colleague2.GetMessage(message);
}
else
{
colleague1.GetMessage(message);
}
}
}
客户端代码
UnitedNationsSecurityCouncil UNSC = new UnitedNationsSecurityCouncil();
让两个具体同事类认识中介者对象(让美国和伊拉克认识安理会)
USA c1 = new USA(UNSC);
Iraq c2 = new Iraq(UNSC);
让中介者认识各个具体同事类对象(让安理会认识伊拉克和美国)
UNSC.Colleague1 = c1;
UNSC.Colleague2 = c2;
具体同事类对象的发送消息都是通过中介者转发的(美国的声明和伊拉克的声明都是通过安理会发出的)
c1.Declare("不准研制核武器,否则要发动战争!");
c2.Declare("我们没有核武器,也不怕侵略");
优缺点
优点:
1.Meidator的出现减少了各个Colleague的耦合,使得可以独立地改变和复用各个Colleague和Mediator,比如任何国家的改变不会影响到其他国家,而只是与安理会发生变化。
2.由于把对象如何协作进行了抽象,将中介作为一个独立的概念并将其封装在一个对象中,这样关注的对象就从对象各自本身的行为转移到它们之间的交互上来,也就是站在一个更宏观的角度去看待系统。比如巴以冲突,本来只能算是国与国之间的矛盾,因此各自的看法可能都比较狭隘,但站在联合国安理会的角度,就可以从全球化、也更客观角度来看待这个问题,在调停和维和上做贡献。
缺点:
具体中介者类ConcreteMediator可能会因为ConcreteColleague的越来越多,而变得非常复杂,反而不容易维护了。
适用场景
一般应用于一组对象以定义良好但是复杂的方式进行通信的场合,以及想指定一个分布在多个类中的行为,而又不想生成太多的子类的场合。