中介者 Mediator
中介者模式是一种行为设计模式,能让你减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互,迫使它们通过一个中介者对象进行合作。
中介者模式提供了一种减少对象之间耦合度的思路。
为什么要使用?
中介者模式的对象职责:
迫使对象之间只能通过一个中介者对象进行合作。 减少对象之间混乱无序的依赖关系。
👉 解决对象之间直接耦合的问题,避免“一处修改多处”的连锁反应出现。
👉 在结构上作为中转,解耦两个服务或系统之间的直接耦合关系。
👉 为了更便捷地统一协同对象之间的通信。
💡 中介者模式的中转作用(结构性)使得对象间的依赖结构变成星型结构,极大地降低对象间的依赖结构耦合度。
💡 中介者模式的协调作用(行为性)能对同类型的对象请求进行统一的处理。
模式结构
- 组件(Component)是各种包含业务逻辑的类。每个组件都有一个指向中介者的引用,该引用被声明为中介者接口类型。组件不知道中介者实际所属的类,因此你可通过将其连接到不同的中介者以使其能在其他程序中复用。组件并不知道其他组件的情况。如果组件内发生了重要事件,它只能通知中介者。中介者收到通知后能轻易地确定发送者,这或许已足以判断接下来需要触发的组件了。
- 中介者(Mediator)接口声明了与组件交流的方法,但通常仅包括一个通知方法。组件可将任意上下文(包括自己的对象)作为该方法的参数,只有这样接收组件和发送者类之间才不会耦合。对于组件来说,中介者看上去完全就是一个黑箱。发送者不知道最终会由谁来处理自己的请求,接收者也不知道最初是谁发出了请求。
- 具体中介者(Concrete Mediator)封装了多种组件间的关系。具体中介者通常会保存所有组件的引用并对其进行管理,甚至有时会对其生命周期进行管理。
中介者模式的类图:
模式实现
该示例使用中介者模式为每个组件都绑定了一个中介者,只允许每个组件与中介者进行互动。中介者可以接收到来自各个组件的消息,并得知来自哪个组件。同时,中介者也可以调用相应组件的方法。
示例程序的类图
代码实现
中介者
package example;
/** 中介者接口 */
public interface Mediator {
/**
* 接收组件发送的信息
* @param sender 组件发送的信息
*/
void apply(Component sender);
}
具体中介者
package example;
/** 具体中介者类 */
public class ConcreteMediator implements Mediator {
/**
* 接收组件发送的信息
* @param sender 组件发送的信息
*/
@Override
public void apply(Component sender) {
System.out.println("中介者接收到来自<" + sender.getClass() + ">的信息...");
}
}
组件
package example;
/** 抽象组件类 */
public abstract class Component {
/** 关联的中介者 */
private Mediator m;
public Component(Mediator m) {
this.m = m;
}
public Mediator getMediator() {
return m;
}
/** 组件方法 */
public abstract void exec();
}
具体组件
package example;
/** 组件A实现类 */
public class ComponentA extends Component {
public ComponentA(Mediator m) {
super(m);
}
/** 组件方法 */
@Override
public void exec() {
System.out.println("调用ComponentA的exec方法...");
super.getMediator().apply(this);
}
}
package example;
/** 组件B实现类 */
public class ComponentB extends Component {
public ComponentB(Mediator m) {
super(m);
}
/** 组件方法 */
@Override
public void exec() {
System.out.println("调用ComponentB的exec方法...");
super.getMediator().apply(this);
}
}
代码测试
import example.*;
/** 测试中介者模式 */
public class Test {
public static void main(String[] args) {
Mediator mediator = new ConcreteMediator();
Component componentA = new ComponentA(mediator);
Component componentB = new ComponentB(mediator);
componentA.exec();
System.out.println("\n---------------------- 分割线 ----------------------\n");
componentB.exec();
}
}
输出结果
调用ComponentA的exec方法...
中介者接收到来自<class example.ComponentA>的信息...
---------------------- 分割线 ----------------------
调用ComponentB的exec方法...
中介者接收到来自<class example.ComponentB>的信息...
常用场景和解决方案
- 系统中对象之间存在复杂的引用关系时,中介者模式能让你将对象间的所有关系抽取成为一个单独的类,以使对于特定组件的修改工作独立于其他组件。
- 在不同情景下复用一些基本行为,导致你需要被迫创建大量组件子类时。中介者模式通过一个中间对象来封装多个类中的共有行为,能让你不需要生成太多的子类。
- 当组件因过于依赖其他组件而无法在不同应用中复用时,中介者模式能让你将所有组件间的关系都包含在中介者中,因此你无需修改组件就能方便地新建中介者类以定义新的组件合作方式。
模式的优缺点
优点 | 缺点 |
---|---|
单一职责原则。你可以将多个组件间的交流抽取到同一位置,使其更易于理解和维护。 | 一段时间后,中介者可能会演化成为上帝对象。 |
开闭原则。你无需修改实际组件就能增加新的中介者。 | |
你可以减轻应用中多个组件间的耦合情况。 | |
你可以更方便地复用各个组件。 |
使用中介者模式的优势
- 减少对象之间的直接交互,间接解耦过多依赖。
- 减少子类的创建数量。例如,在不同情景下复用一些基本行为,导致你需要被迫创建大量组件子类时。
- 简化各系统的设计和实现。
- 通过新建中间层快速扩展新功能,提升代码扩展性。
使用中介者模式的劣势
- 中介者类中的交互逻辑可能变得非常复杂且难以维护。
- 变成了新的重度依赖对象。
- 需要知道所有对象的交互逻辑。
拓展知识
- 外观模式和中介者的职责类似:它们都尝试在大量紧密耦合的类中组织起合作。
- 外观为子系统中的所有对象定义了一个简单接口,但是它不提供任何新功能。子系统本身不会意识到外观的存在。子系统中的对象可以直接进行交流。
- 中介者将系统中组件的沟通行为中心化。各组件只知道中介者对象,无法直接相互交流。
- 中介者和观察者之间的区别:
- 中介者的主要目标是消除一系列系统组件之间的相互依赖。这些组件将依赖于同一个中介者对象。
- 观察者的目标是在对象之间建立动态的单向连接,使得部分对象可作为其他对象的附属发挥作用。
- 对于中介者和观察者,在大部分情况下,你可以使用其中一种模式,而有时可以同时使用。
- 有一种流行的中介者模式实现方式依赖于观察者。中介者对象担当发布者的角色,其他组件则作为订阅者,可以订阅中介者的事件或取消订阅。当中介者以这种方式实现时,它可能看上去与观察者非常相似。你也可以永久性地将所有组件链接到同一个中介者对象。这种实现方式和观察者并不相同,但这仍是一种中介者模式。
- 假设有一个程序,其所有的组件都变成了发布者,它们之间可以相互建立动态连接。这样程序中就没有中心化的中介者对象,而只有一些分布式的观察者。
🔙 设计模式
📌最后:希望本文能够给您提供帮助,文章中有不懂或不正确的地方,请在下方评论区💬留言!
🔗参考文献:
▶️ bilibili-趣学设计模式;黄靖锋. --拉勾教育
📖 图解设计模式 /(日)结城浩著;杨文轩译. --北京:人民邮电出版社,2017.1