中介者模式

对象行为型模式

模式动机

考虑一个线上聊天场景(比如QQ),如果用户和用户直接聊天的设计,那么用户对象之间存在很强的耦合,会导致:

  • 系统结构复杂:用户之间的连线太多了,几乎两两之间都存在耦合关系,一个对象发生变化可能需要跟踪所有和它产生耦合的用户对象
  • 对象可重用性差:由于一个对象和其它对象之间有很强的耦合,如果没有其他对象的支持,一个对象很难被了一个模块重用,这些互相耦合的对象更像揉在一起的一个整体,职责混乱不清晰,不符合单一职责原则
  • 系统扩展性低:每增加一个新的用户对象都需要和几乎所有原对象之间产生引用关系,进一步加强耦合且操作上并不灵活,体现为可扩展性较差

根据单一职责原则,对象的职责应该尽可能细化,最好只有一个职责;对于一个模块,如果它确实包含了许多对象,并且可能存在相互的引用,那我们也应该尽可能减少两两之间存在引用的关系使其成为松耦合系统,这就是中介者模式的动机

应用

中介者模式使用一个中介对象来封装一系列对象交互,使得各对象之间不必显式地互相引用,从而使其松耦合;并且中介者的存在可以独立地改变对象之间的交互。中介者模式又叫调停者模式。

中介者模式包含如下角色:

  • 抽象中介者Mediator
  • 具体中介者ConcreteMediator
  • 抽象同事类Colleague
  • 具体同事类ConcreteColleague

中介者模式可以使对象之间的关系急剧减少 O(n2)O(n)O(n^2)\rightarrow O(n)

中介者主要承担两方面的职责:

  • 中转作用:这是结构上的支持,中转作用的存在使得同事之间不必显式引用其他同事,需要通信时告诉中介者即可,让中介者转发,这样大家都只需要和中介者产生耦合即可
  • 协调作用:这是行为上的支持,中介者可以进一步封装同事之间的关系,同事和中介者交互时不需要指明中介者需要做什么,而是让中介者根据封装好的逻辑自行进一步处理。

典型代码如下:

public abstract class Mediator {
protected ArrayList colleagues;
public void register(Colleague colleague) {
colleagues.add(colleague);
}
public abstract void operation();
}
public class ConcreteMediator extends Mediator {
public void operation() {
// ...
((Colleague)(colleagues.get(0))).method1();
// ...
}
}

public abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator=mediator;
}
public abstract void method1();
public abstract void method2();
}
public class ConcreteColleague extends Colleague {
public ConcreteColleague(Mediator mediator) {
super(mediator);
}
public void method1() {
// ...
}
public void method2() {
mediator.operation1();
}
}

实例:虚拟聊天室

某论坛系统欲增加一个虚拟聊天室,允许论坛会员通过该聊天室进行信息交流,普通会员(CommonMember)可以给其他会员发送文本信息,钻石会员(DiamondMember)既可以给其他会员发送文本信息,还可以发送图片信息。该聊天室可以对不雅字符进行过滤,如“日”等字符;还可以对发送的图片大小进行控制。

优点

  1. 简化对象间的交互
  2. 各同事之间解耦
  3. 减少子类的生成
  4. 简化各同事类的设计和实现

缺点

在具体中介者类中包含了同事之间的交互细节,可能会导致中介者类非常复杂,难以维护

适用场合

  • 对象之间存在复杂的引用关系,尤其是两两之间存在大量引用
  • 一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象
  • 通过一个中间类封装多个类中的行为,但又不想生成太多子类。此时可以引入中介者,在中介者中定义对象交互的公共行为,如需改变行为可以增加新的中介者类
  1. 中介者模式在事件驱动软件中应用较多,比如GUI应用程序
  2. MVC是Java EE的一个基本模式,其中的Controller就是一种中介者

模式扩展

中介者模式 + 迪米特法则

在中介者模式中,通过创造出一个中介者对象, 将系统中有关的对象所引用的其他对象数目减少到最少,使得一个对象与其同事之间的相互作用这个对象与中介者对象之间的相互作用所取代。因此, 中介者模式就是迪米特法则的一个典型应用

中介者模式 + GUI开发

中介者模式可以很方便地应用于GUI开发,在复杂界面中可能存在多个界面组件之间的交互,这时就可以引入中介者来处理复杂的交互关系。将界面组件视为同事类,把它们之间的引用和控制关系交给中介者类负责,可以简化系统的交互,降低耦合。

(•‿•)