1. 中介者模式介绍
中介者模式(Mediator Pattern)是一种行为设计模式,它通过将对象之间的直接通信转移到一个中介对象中,来减少对象之间的耦合度。这种模式被用来处理一个对象与其他对象之间的交互,使得各对象之间不需要直接相互了解。
在中介者模式中,中介者对象负责协调和控制其他对象的交互,而对象之间不再直接通信,而是通过中介者来进行通信。这样可以减少对象之间的依赖关系,使系统更易于维护和扩展。
2. 关键思想
中介者模式的关键思想是通过引入一个中介者对象,来解耦系统中各个对象之间的直接交互关系。它的目的是减少对象之间的依赖关系,使得系统更加灵活、可维护和可扩展。
以下是中介者模式的关键思想:
- 对象解耦: 中介者模式的主要目标是将系统中各个对象之间的直接联系减少到最小,从而降低系统的复杂性。对象不再直接与其他对象通信,而是通过中介者进行通信。
- 集中控制: 中介者模式引入了一个中介者对象,该对象负责协调和控制各个对象之间的交互。中介者充当了对象之间的集中调度器,负责处理对象之间的通信和协作。
- 减少耦合: 通过减少对象之间的直接依赖关系,中介者模式可以降低系统中各个对象之间的耦合度。这使得系统更加灵活,可以更容易地修改、扩展或替换其中的对象。
- 对象独立性: 各个对象在中介者模式中是相对独立的,它们不需要了解彼此的实现细节,只需要通过中介者来进行通信。这增加了对象的独立性,使得每个对象更容易被理解和维护。
- 集中化管理: 中介者模式将系统中对象之间的交互集中到一个中介者对象中进行管理,使得系统更容易管理和维护。当系统中有多个对象需要协同工作时,中介者充当了协调者的角色。
- 降低系统复杂性: 中介者模式可以降低系统的复杂性,尤其在系统中有多个对象之间复杂的交互关系时。通过引入中介者,将复杂的交互逻辑集中管理,使系统更容易理解和维护。
总体而言,中介者模式通过引入中介者对象,将对象之间的通信集中化管理,从而提高系统的可维护性和扩展性。这种模式特别适用于多个对象之间存在复杂的交互关系的场景。
3. 实现方式
- 定义中介者接口: 创建一个中介者接口,其中包含用于各对象交互的方法。
/** * Mediator(中介者)接口定义了对象之间通信的方法。 * 具体的中介者类将实现这个接口,负责协调和控制对象之间的交互。 */ public interface Mediator { /** * 向特定同事对象发送消息,通常由具体的同事对象调用。 * * @param message 要发送的消息内容 * @param colleague 要接收消息的同事对象 */ void sendMessage(String message, Colleague colleague); }
这个接口定义了中介者的职责,即协调和控制对象之间的通信。通过 sendMessage 方法,同事对象可以向中介者发送消息,中介者将负责将消息传递给其他相关的同事对象。在具体的中介者类中,实现这个接口来提供实际的协调逻辑。
- 实现中介者类: 创建一个实现中介者接口的具体中介者类,负责协调和控制对象之间的交互。
/** * ConcreteMediator(具体中介者)类实现了中介者接口,负责协调和控制同事对象之间的交互。 * 具体中介者类通常持有对所有相关同事对象的引用,并根据接收到的消息进行相应的处理。 */ public class ConcreteMediator implements Mediator { private Colleague colleague1; private Colleague colleague2; /** * 设置第一个同事对象,用于注册到中介者。 * * @param colleague 要注册的第一个同事对象 */ public void setColleague1(Colleague colleague) { this.colleague1 = colleague; } /** * 设置第二个同事对象,用于注册到中介者。 * * @param colleague 要注册的第二个同事对象 */ public void setColleague2(Colleague colleague) { this.colleague2 = colleague; } /** * 当某个同事对象发送消息时,中介者将根据发送消息的同事对象, * 将消息传递给其他相关的同事对象,以实现对象之间的通信和协作。 * * @param message 要发送的消息内容 * @param colleague 发送消息的同事对象 */ @Override public void sendMessage(String message, Colleague colleague) { // 如果消息来自 colleague1,则将消息传递给 colleague2 if (colleague == colleague1) { colleague2.receiveMessage(message); } // 如果消息来自 colleague2,则将消息传递给 colleague1 else if (colleague == colleague2) { colleague1.receiveMessage(message); } } }
在这个具体中介者类中,通过实现 Mediator 接口,它负责处理来自同事对象的消息,并协调将消息传递给其他相关的同事对象。具体中介者类通常包含对所有相关同事对象的引用,并根据具体的业务逻辑进行消息的转发和处理。
- 定义同事类: 创建同事类,实现同事接口,并在其中保存对中介者的引用。
/** * Colleague(同事)抽象类定义了同事对象的基本行为,包括发送和接收消息。 * 具体的同事类将继承这个抽象类,并实现具体的发送和接收消息的方法。 */ public abstract class Colleague { protected Mediator mediator; /** * 构造函数,用于注入中介者对象。 * * @param mediator 中介者对象,用于同事对象之间的通信 */ public Colleague(Mediator mediator) { this.mediator = mediator; } /** * 发送消息的抽象方法,具体实现由子类实现。 * * @param message 要发送的消息内容 */ public abstract void send(String message); /** * 接收消息的抽象方法,具体实现由子类实现。 * * @param message 接收到的消息内容 */ public abstract void receiveMessage(String message); }
这个抽象类定义了同事对象的基本行为,其中 send 方法用于发送消息,receiveMessage 方法用于接收消息。由于同事对象之间的通信需要通过中介者,因此构造函数中注入了中介者对象。具体的同事类将继承这个抽象类,并实现具体的发送和接收消息的逻辑。这样,同事对象可以通过中介者进行通信,而不需要直接依赖于其他同事对象。
- 实现具体同事类: 创建具体的同事类,继承自同事类,并实现相应的方法。
/** * ConcreteColleague1(具体同事类1)继承自 Colleague 抽象类, * 实现了具体的发送和接收消息的逻辑。 */ public class ConcreteColleague1 extends Colleague { /** * 构造函数,用于注入中介者对象。 * * @param mediator 中介者对象,用于同事对象之间的通信 */ public ConcreteColleague1(Mediator mediator) { super(mediator); } /** * 发送消息的具体实现,调用中介者的 sendMessage 方法。 * * @param message 要发送的消息内容 */ @Override public void send(String message) { mediator.sendMessage(message, this); } /** * 接收消息的具体实现,输出接收到的消息内容。 * * @param message 接收到的消息内容 */ @Override public void receiveMessage(String message) { System.out.println("ConcreteColleague1 received message: " + message); } }
/** * ConcreteColleague2(具体同事类2)继承自 Colleague 抽象类, * 实现了具体的发送和接收消息的逻辑。 */ public class ConcreteColleague2 extends Colleague { /** * 构造函数,用于注入中介者对象。 * * @param mediator 中介者对象,用于同事对象之间的通信 */ public ConcreteColleague2(Mediator mediator) { super(mediator); } /** * 发送消息的具体实现,调用中介者的 sendMessage 方法。 * * @param message 要发送的消息内容 */ @Override public void send(String message) { mediator.sendMessage(message, this); } /** * 接收消息的具体实现,输出接收到的消息内容。 * * @param message 接收到的消息内容 */ @Override public void receiveMessage(String message) { System.out.println("ConcreteColleague2 received message: " + message); } }
- 使用中介者模式: 在客户端代码中创建中介者对象、同事对象,并将同事对象注册到中介者中。
/** * 客户端代码用于演示中介者模式的使用。 */ public class Client { public static void main(String[] args) { // 创建具体中介者对象 ConcreteMediator mediator = new ConcreteMediator(); // 创建具体同事对象并注册到中介者 ConcreteColleague1 colleague1 = new ConcreteColleague1(mediator); ConcreteColleague2 colleague2 = new ConcreteColleague2(mediator); mediator.setColleague1(colleague1); mediator.setColleague2(colleague2); // 具体同事对象通过中介者进行通信 colleague1.send("Hello from Colleague1"); colleague2.send("Hi from Colleague2"); } }
这样,通过中介者模式,同事对象之间的交互被封装在中介者对象中,从而实现了对象之间的解耦。这对于复杂的系统中有多个对象需要协同工作时,可以提高系统的可维护性和扩展性。
示例代码
让我们考虑一个简单的聊天室系统。在这个系统中,我们有用户(User)和聊天室(ChatRoom)。用户可以发送消息到聊天室,而聊天室负责将消息广播给所有其他用户。这是一个中介者模式的典型应用。
import java.util.ArrayList; import java.util.List; // 中介者接口 interface ChatMediator { void sendMessage(String message, User user); } // 具体中介者类 class ChatRoom implements ChatMediator { private List<User> users; public ChatRoom() { this.users = new ArrayList<>(); } // 注册用户到聊天室 public void addUser(User user) { users.add(user); } @Override public void sendMessage(String message, User user) { // 中介者负责将消息广播给其他用户 for (User u : users) { if (u != user) { u.receiveMessage(message); } } } } // 同事类 - 用户 class User { private String name; private ChatMediator mediator; public User(String name, ChatMediator mediator) { this.name = name; this.mediator = mediator; } // 发送消息给聊天室 public void sendMessage(String message) { System.out.println(name + " sends message: " + message); mediator.sendMessage(message, this); } // 接收其他用户的消息 public void receiveMessage(String message) { System.out.println(name + " receives message: " + message); } } // 客户端代码 public class Client { public static void main(String[] args) { // 创建聊天室中介者 ChatRoom chatRoom = new ChatRoom(); // 创建用户并注册到聊天室 User user1 = new User("Alice", chatRoom); User user2 = new User("Bob", chatRoom); User user3 = new User("Charlie", chatRoom); chatRoom.addUser(user1); chatRoom.addUser(user2); chatRoom.addUser(user3); // 用户发送消息到聊天室 user1.sendMessage("Hello, everyone!"); user2.sendMessage("Hi, Alice!"); } }
- ChatMediator 是中介者接口,定义了消息的发送方法。
- ChatRoom 是具体中介者类,负责协调用户之间的消息通信。
- User 是同事类,表示聊天室中的用户,能够发送消息给聊天室,并接收其他用户发送的消息。
- 客户端代码创建了一个聊天室中介者和多个用户,并演示了用户之间通过中介者进行消息通信的过程。
这个例子中,中介者模式帮助我们实现了用户之间的松散耦合,用户不需要直接知道彼此的存在,而是通过中介者进行通信。这使得系统更加灵活、易于扩展和维护。
要点:
- 减少耦合: 中介者模式通过引入中介者对象,将系统中对象之间的直接通信变为通过中介者进行,从而降低了对象之间的耦合度。
- 集中控制: 中介者模式集中了对象之间的通信和协作,中介者负责协调对象之间的交互,使得系统更容易管理和维护。
- 对象独立性: 各个同事对象在中介者模式中是相对独立的,它们不直接知道彼此的存在,而是通过中介者进行通信,增强了对象的独立性。
- 易于扩展: 中介者模式使得系统更容易扩展,当需要添加新的同事对象时,只需注册到中介者即可,不需要修改已有对象的代码。
- 松散耦合: 中介者模式实现了松散耦合,使得对象之间的交互更加灵活,易于维护和修改。
注意事项:
- 单一职责原则: 中介者模式要求中介者对象集中处理对象之间的通信,因此需要确保中介者对象不涉及过多的业务逻辑,遵循单一职责原则。
- 中介者的复杂性: 随着系统中对象和其交互关系的增多,中介者对象的复杂性可能会增加。因此,需要注意中介者的设计,确保它能够有效地协调对象之间的交互。
- 不适用于所有场景: 中介者模式并不适用于所有的系统设计场景。在一些简单的情况下,对象之间的直接通信可能更为合适。中介者模式主要用于系统中对象之间的复杂交互关系。
- 避免过度集中化: 尽管中介者模式集中了对象之间的通信,但过度集中化可能导致中介者对象过于庞大和复杂。需要在设计中注意平衡,确保中介者的职责适度。
- 避免循环依赖: 中介者模式中的对象通过中介者进行通信,需要注意避免循环依赖的情况,以免导致系统难以维护。适当的设计和引入抽象类可以帮助解决循环依赖的问题。
优点:
- 减少耦合: 中介者模式通过将对象之间的直接通信转为通过中介者进行,降低了对象之间的耦合度,使得系统更加灵活、易于维护和扩展。
- 集中控制: 中介者模式集中了对象之间的交互逻辑,使得系统的结构更加清晰,易于理解和维护。中介者负责协调对象之间的通信,避免了对象之间的混乱关系。
- 对象独立性: 各个同事对象在中介者模式中是相对独立的,它们不需要直接知道彼此的存在,而是通过中介者进行通信,增强了对象的独立性。
- 易于扩展: 中介者模式使得系统更容易扩展,当需要添加新的同事对象时,只需注册到中介者即可,不需要修改已有对象的代码。
- 易于维护: 中介者模式将对象之间的交互逻辑集中在中介者中,使得修改和维护变得更加容易。不同对象的变化对其他对象的影响较小,维护成本相对较低。
缺点:
- 中介者过于庞大: 随着系统中对象和其交互关系的增多,中介者对象可能会变得过于庞大,包含大量的业务逻辑。这可能导致中介者对象的复杂性增加,不易维护。
- 对象间通信效率低: 中介者模式将对象之间的通信集中在中介者中,可能导致对象间直接通信的效率降低,特别是在中介者对象变得复杂时。
- 不适用于简单场景: 中介者模式并不适用于所有的系统设计场景。在一些简单的情况下,对象之间的直接通信可能更为合适。
应用场景:
- 系统中对象之间存在复杂的交互关系: 当系统中的对象之间存在复杂的交互关系,且对象之间的通信难以维护时,可以考虑使用中介者模式。
- 对象之间存在强耦合: 如果系统中的对象之间存在强耦合,导致一个对象的改变会影响其他对象,可以引入中介者模式来减少对象之间的直接依赖。
- 多个对象共享状态: 当多个对象共享某些状态,并且需要及时同步这些状态时,中介者模式可以提供一个中心化的方式进行管理。
- 系统需要实现松散耦合: 当系统需要实现松散耦合,使得对象之间的交互更加灵活、易于维护和扩展时,中介者模式是一个合适的选择。