在现实生活中,常常会出现好多对象之间存在复杂的交互关系,这种交互关系常常是“网状结构”,它要求每个对象都必须知道它需要交互的对象。例如,每个人必须记住他(她)所有朋友的电话;而且,朋友中如果有人的电话修改了,他(她)必须让其他所有的朋友一起修改,“牵一发而动全身”非常复杂。如果把这种“网状结构”改为“星形结构”的话,将大大降低它们之间的“耦合性”,这时只要找一个“中介者”就可以了。
软件的开发过程中这样的例子也很多 ,在 MVC 框架中,控制器(C)就是模型(M)和视图(V)的中介者;还有大家常用的 QQ 聊天程序的“中介者”是 QQ 服务器。
模式的定义与特点
中介者(Mediator)模式的定义:定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。
中介者模式是一种对象行为型模式,其主要优点如下。
- 类之间各司其职,符合迪米特法则。
- 降低了对象之间的耦合性,使得对象易于独立地被复用。
- 将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展。
其主要缺点是:中介者模式将原本多个对象直接的相互依赖变成了中介者和多个同事类的依赖关系。当同事类越多时,中介者就会越臃肿,变得复杂且难以维护。
模式的结构与实现
中介者模式实现的关键是找出“中介者”中介者可以将所有成员注册(register方法)在中介者内的列表内并且为该成员得到该中介者对象,除了注册方法中介者还有转发方法,目的是为了给具体同事成员提供一个转发方法:除了自己其他所有人执行接收方法。
我们应用时先创建中介者,在声明所有的同事对象,把同事注册(register)进中介者中,注册方法内执行数组add方法以及将该中介对象赋予该同事对象以便后续调用中介者的转发方法,然后我们执行具体成员的发送方法后先执行自定义发送内容再(固定流程)调用中介的转发方法,使其他成员执行收到。
//抽象中介者
public interface Mediator
{
void register(Colleague colleague);
void relay(Colleague cl);
}
//具体中介者
public class ConcreteMediator :Mediator
{
private List<Colleague> colleagues = new List<Colleague>();
public void register(Colleague colleague)
{
if (!colleagues.Contains(colleague))
{
colleagues.Add(colleague);
colleague.setMediator(this);
}
}
/// <summary>
/// 转发方法
/// </summary>
/// <param name="cl"></param>自己不触发
public void relay(Colleague cl)
{
foreach (var colleague in colleagues)
{
if (!colleague.Equals(cl))
{
colleague.receive();
}
}
}
}
//抽象同事类
public abstract class Colleague
{
protected Mediator mediator;
public void setMediator(Mediator mediator)
{
this.mediator = mediator;
}
public abstract void receive();
public abstract void send();
}
//具体同事类
public class ConcreteColleagueA : Colleague
{
public override void receive()
{
Debug.Log("具体同事类A收到请求");
}
public override void send()
{
Debug.Log("具体同事类A发出请求");
mediator.relay(this);//请中介者转发
}
}
public class ConcreteColleagueB : Colleague
{
public override void receive()
{
Debug.Log("具体同事类B收到请求");
}
public override void send()
{
Debug.Log("具体同事类B发出请求");
mediator.relay(this);
}
}
void Start()
{
Mediator mediator = new ConcreteMediator();//创建中介者
//创建具体同事AB记在通讯录内
Colleague cA = new ConcreteColleagueA();
mediator.register(cA);
Colleague cB = new ConcreteColleagueB();
mediator.register(cB);
//A发消息,其他所有人(此处仅有B接收)
cA.send();
}
//执行结果
//具体同事类A发出请求
//具体同事类B收到请求
模式的应用场景
前面分析了中介者模式的结构与特点,下面分析其以下应用场景
- 当对象之间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时。
- 当想创建一个运行于多个类之间的对象,又不想生成新的子类时。
模式的扩展
在实际开发中,通常采用以下两种方法来简化中介者模式,使开发变得更简单。
- 不定义中介者接口,把具体中介者对象实现成为单例。
- 同事对象不持有中介者,而是在需要的时候直接获取中介者对象并调用。