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)