Java - GoF设计模式详解18(中介者模式)
作者:hangge | 2023-06-20 08:55
十八、中介者模式
1,基本介绍
(1)中介者模式(Mediator)用一个中介者对象封装一系列对象交互,以防止这些对象直接交互,从而使这些对象耦合松散,并且可以独立地改变它们的交互。
(2)该模式中包含的角色及其职责如下:
- 抽象中介者 (Mediator):定义一个接口用于与各同事对象通信。
- 具体中介者 (ConcreteMediator):实现中介者接口,定义一个同事类的集合,协调各个同事对象的交互关系。
- 抽象同事类 (Colleague):定义同事的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
- 具体同事类 (Concrete Colleague):实现同事类的接口,在需要与其他同事对象交互时,通过中介者对象来实现。

2,使用样例
(1)首先我们定义了一个抽象中介者类 Mediator,包含注册同事和转发消息这两个方法:
// 抽象中介者
interface Mediator {
// 注册同事
void register(Colleague colleague);
// 转发消息
void relay(String message, Colleague colleague);
}
(2)接着定义具体中介者类 ConcreteMediator 实现抽象中介者类,它维护了一个同事列表,并且实现了在中介者中注册同事和转发消息的方法。
// 具体中介者
class ConcreteMediator implements Mediator {
// 同事列表
private List<Colleague> colleagues;
public ConcreteMediator() {
this.colleagues = new ArrayList<>();
}
@Override
public void register(Colleague colleague) {
if (!colleagues.contains(colleague)) {
colleagues.add(colleague);
}
}
@Override
public void relay(String message, Colleague colleague) {
colleagues.forEach(c -> {
if (!c.equals(colleague)) {
c.receive(message);
}
});
}
}
(3)然后定义一个抽象同事类 Colleague,声明了接收消息和发送消息的方法。
// 抽象同事类
abstract class Colleague {
// 中介者
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
// 发送消息
public abstract void receive(String message);
// 接收消息
public abstract void send(String message);
}
(4)接着定义两个具体同事类 ConcreteColleagueA 和 ConcreteColleagueB 分别继承了抽象同事类,并实现了接收消息和发送消息的方法。
// 具体同事类A
class ConcreteColleagueA extends Colleague {
public ConcreteColleagueA(Mediator mediator) {
super(mediator);
}
// 发送消息
@Override
public void send(String message) {
System.out.println("同事A发送消息:" + message);
mediator.relay(message, this);
}
// 接收消息
@Override
public void receive(String message) {
System.out.println("同事A收到消息:" + message);
}
}
// 具体同事类B
public class ConcreteColleagueB extends Colleague {
public ConcreteColleagueB(Mediator mediator) {
super(mediator);
}
// 发送消息
@Override
public void send(String message) {
System.out.println("同事B发送消息:" + message);
mediator.relay(message, this);
}
// 接收消息
@Override
public void receive(String message) {
System.out.println("同事B收到消息:" + message);
}
}
(5)最后测试一下,们创建了一个具体中介者对象,并创建了两个具体同事对象。然后将这两个同事对象注册到中介者中,并发送消息:
- 我们调用同事 A 的发送消息方法,这时同事 A 会调用中介者的转发消息方法,中介者收到消息后会转发给其他同事,于是同事 B 会收到消息。
- 我们调用同事 B 的发送消息方法,同样会调用中介者的转发消息方法,中介者会转发给其他同事,于是同事 A 会收到消息。
public class Test {
public static void main(String[] args) {
// 创建一个具体中介者对象
Mediator mediator = new ConcreteMediator();
// 创建了两个具体同事对象
Colleague colleagueA = new ConcreteColleagueA(mediator);
Colleague colleagueB = new ConcreteColleagueB(mediator);
// 将这两个同事对象注册到中介者中
mediator.register(colleagueA);
mediator.register(colleagueB);
// 调用同事 A 的发送消息方法
colleagueA.send("hangge.com");
// 调用同事 B 的发送消息方法
colleagueB.send("航歌");
}
}
附一:JDK 中的中介者模式
1,Timer 中的中介者模式
(1)在 JDK 的 java.util.Timer 类中,使用了中介者模式来管理定时器任务。java.util.Timer 类维护了一个任务列表,并使用一个线程来调度这些任务。每个任务都是一个 TimerTask 对象,它们之间通过 Timer 对象进行交互。
- Timer 是中介者,通过 schedule 方法定时调度我们写的各种任务,将任务添加到 TaskQueue 任务队列中,给 TimerThread 执行,让任务与执行线程解耦。
- TimerTask 是抽象同事类
- 我们自己写的任务则是具体同事类。
public class Test {
public static void main(String[] args) {
// 初始化Timer定时器对象
Timer timer = new Timer();
// 可调度的任务1
TimerTask task1 = new TimerTask() {
@Override
public void run() {
System.out.println("Task 1 executed.");
}
};
// 可调度的任务2
TimerTask task2 = new TimerTask() {
@Override
public void run() {
System.out.println("Task 2 executed.");
}
};
// 延迟1秒后执行,之后每2秒定时执行一次
timer.schedule(task1, 1000, 2000);
// 延迟2秒后执行,之后每2秒定时执行一次
timer.schedule(task2, 2000, 2000);
}
}
2,Executor 接口和 ExecutorService 接口的中介者模式
(1)在 JDK 的 java.util.concurrent.Executor 接口和 java.util.concurrent.ExecutorService 接口中,使用了中介者模式来管理线程池。这些接口提供了一种通用的方法来执行异步任务,可以将任务提交到线程池中执行,而无需直接创建新的线程。线程池维护了一组工作线程,并使用中介者模式来管理它们之间的交互。
(2)下面是一个使用 java.util.concurrent.ExecutorService 接口创建线程池的示例代码。在这个示例代码中,我们可以看到以下几个角色:
- ExecutorService 接口是中介者,它负责管理工作线程之间的交互。
- Executors 类是具体中介者,它实现了 ExecutorService 接口,并提供了一组静态工厂方法来创建线程池。
- Executor 接口是抽象同事类(Executor 也是的 ExecutorService 父接口),它定义了线程池的基本操作。
- Runnable 接口是抽象同事类,它定义了任务的基本操作。
- 匿名内部类是具体同事类,它实现了 Runnable 接口,并被提交给线程池执行。
public class Test {
public static void main(String[] args) {
// 创建了一个线程池
ExecutorService executor = Executors.newFixedThreadPool(5);
// 提交任务1给线程池执行
executor.submit(new Runnable() {
@Override
public void run() {
System.out.println("运行任务1");
}
});
// 提交任务2给线程池执行
executor.submit(new Runnable() {
@Override
public void run() {
System.out.println("运行任务2");
}
});
// 关闭线程池
executor.shutdown();
}
}
附二:Spring 中的中介者模式
1,使用 ApplicationContext 来实现中介者模式
(1)在 Spring 中,中介者模式可以通过使用 Spring 的 ApplicationContext 来实现。ApplicationContext 可以作为一个中介者,用于在不同的对象之间传递消息。
- 比如:假设我们有两个 bean,一个是消息生产者,另一个是消息消费者。生产者 bean 在生产消息时,可以将消息发布到 ApplicationContext 中,而消费者 bean 可以监听消息并进行相应的处理。这样,ApplicationContext 就可以在生产者和消费者之间传递消息,作为这两个 bean 之间的中介者。
(2)下面是一个简单的例子,展示了如何使用 ApplicationContext 在两个 bean 之间传递消息。
// 消息生产者
@Component
public class MessageProducer {
// 注入 ApplicationContext
@Autowired
private ApplicationContext applicationContext;
public void produceMessage(String message) {
// 发布消息
applicationContext.publishEvent(new MessageEvent(this, message));
}
}
// 消息消费者
@Component
public class MessageConsumer {
// 使用 @EventListener 注解来监听消息
@EventListener
public void onMessage(MessageEvent event) {
String message = event.getMessage();
// 根据收到的消息执行相应的处理
}
}
public class MessageEvent extends ApplicationEvent {
private String message;
public MessageEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
2,使用 JMS 模块来实现中介者模式
(1)JMS (Java Message Service) 是一种 Java 消息中间件,可以在不同的应用之间传递消息。Spring 提供了对 JMS 的支持,可以方便地在 Spring 应用中使用 JMS。
(2)关于 JMS 更消息的用法,可以参考我之前写的文章:
全部评论(0)