1. 中介者模式为什么我们需要一个中间人想象一下这样的场景你正在开发一个复杂的用户界面系统里面有几十个按钮、输入框、下拉菜单等组件。这些组件之间需要频繁通信——比如点击某个按钮要禁用三个输入框修改下拉菜单要更新五个标签的显示内容。如果让每个组件都直接与其他组件交互代码很快就会变成一团乱麻。这就是中介者模式Mediator Pattern要解决的问题。它通过引入一个中介对象来封装一组对象之间的交互使这些对象不再显式地相互引用从而降低耦合度。就像现实生活中的房屋中介买卖双方不需要直接打交道所有沟通都通过中介完成。2. 中介者模式的核心结构与实现2.1 UML类图解析中介者模式的核心参与者包括Mediator抽象中介者定义同事对象到中介者对象的接口ConcreteMediator具体中介者实现抽象中介者的接口协调各同事对象的交互Colleague抽象同事类知道其中介者对象在需要与其他同事通信时通过中介者完成ConcreteColleague具体同事类实现自己的行为当需要与其他同事通信时通过中介者转发请求// 抽象中介者 interface Mediator { void notify(Colleague sender, String event); } // 具体中介者 class ConcreteMediator implements Mediator { private ListColleague colleagues new ArrayList(); void addColleague(Colleague colleague) { colleagues.add(colleague); } Override public void notify(Colleague sender, String event) { for (Colleague colleague : colleagues) { if (colleague ! sender) { colleague.receive(event); } } } } // 抽象同事类 abstract class Colleague { protected Mediator mediator; public Colleague(Mediator mediator) { this.mediator mediator; } abstract void send(String event); abstract void receive(String event); } // 具体同事类 class ConcreteColleagueA extends Colleague { public ConcreteColleagueA(Mediator mediator) { super(mediator); } Override void send(String event) { System.out.println(ColleagueA sends: event); mediator.notify(this, event); } Override void receive(String event) { System.out.println(ColleagueA receives: event); } }2.2 实际应用中的变体在实际开发中中介者模式有几种常见变体事件总线模式中介者维护一个事件订阅/发布系统控制器模式将中介者实现为控制器处理视图组件间的交互协调器模式中介者负责协调多个服务或子系统的工作流3. 中介者模式的典型应用场景3.1 GUI开发中的组件交互现代前端框架如React、Vue都内置了类似中介者的机制。以React为例class FormMediator { constructor() { this.components []; } register(component) { this.components.push(component); } notify(source, event) { this.components.forEach(component { if (component ! source) { component.handleEvent(event); } }); } } // 使用中介者的React组件 class MyInput extends React.Component { componentDidMount() { this.props.mediator.register(this); } handleChange (e) { this.props.mediator.notify(this, { type: INPUT_CHANGE, value: e.target.value }); }; handleEvent(event) { if (event.type OTHER_COMPONENT_EVENT) { // 处理来自其他组件的事件 } } render() { return input onChange{this.handleChange} /; } }3.2 聊天室系统的实现聊天室是中介者模式的经典案例。用户同事类不直接相互发送消息而是通过聊天室服务器中介者转发class ChatRoom: def __init__(self): self.users [] def add_user(self, user): self.users.append(user) def send_message(self, sender, message): for user in self.users: if user ! sender: user.receive(message) class User: def __init__(self, name, chat_room): self.name name self.chat_room chat_room def send(self, message): print(f{self.name} sends: {message}) self.chat_room.send_message(self, message) def receive(self, message): print(f{self.name} receives: {message}) # 使用示例 room ChatRoom() alice User(Alice, room) bob User(Bob, room) room.add_user(alice) room.add_user(bob) alice.send(Hi Bob!) # Alice发送的消息通过ChatRoom转发给Bob3.3 游戏开发中的角色交互在游戏开发中多个游戏实体角色、物品、环境等之间需要复杂交互。使用中介者模式可以避免直接的网状依赖// 游戏事件中介者 public class GameMediator : MonoBehaviour { private ListIGameEntity entities new ListIGameEntity(); public void RegisterEntity(IGameEntity entity) { entities.Add(entity); } public void BroadcastEvent(GameEvent gameEvent, IGameEntity sender) { foreach (var entity in entities) { if (entity ! sender) { entity.HandleEvent(gameEvent); } } } } // 游戏实体接口 public interface IGameEntity { void HandleEvent(GameEvent gameEvent); } // 具体实体玩家角色 public class Player : MonoBehaviour, IGameEntity { [SerializeField] private GameMediator mediator; private void Start() { mediator.RegisterEntity(this); } public void HandleEvent(GameEvent gameEvent) { // 处理来自其他实体的事件 } private void OnTriggerEnter(Collider other) { // 当玩家触发某事件时通知中介者 mediator.BroadcastEvent(new PlayerTriggerEvent(this), this); } }4. 中介者模式的优缺点与适用场景4.1 优势分析降低耦合度将网状交互变为星型交互对象只需知道中介者简化对象协议一对多交互由中介者管理同事类接口可以更简单控制集中化交互逻辑集中在中介者中便于理解和维护复用性提高通过替换中介者可以改变系统行为而不需要修改各个同事类4.2 潜在缺点中介者可能变得过于复杂随着交互逻辑增加中介者可能变成上帝对象性能开销所有通信都要通过中介者转发可能引入额外开销调试困难交互逻辑集中在中介者中可能使问题定位变得困难4.3 何时使用中介者模式适合使用中介者模式的场景包括对象之间存在复杂的网状引用关系难以复用某个对象因为它需要与其他许多对象通信想在多个类之间分布行为又不想生成太多子类系统组件间的交互定义明确但复杂5. 中介者模式的最佳实践与常见陷阱5.1 实现建议明确中介者的职责边界中介者应该只负责协调不包含业务逻辑避免让中介者知道太多具体同事类的细节使用接口而非具体类同事类应该通过抽象中介者接口通信具体中介者实现应该可以替换考虑使用观察者模式组合让同事类作为观察者注册到中介者中介者通过通知机制广播事件5.2 常见错误与解决方案问题1中介者变成了上帝对象症状中介者类膨胀到数千行代码包含太多业务逻辑解决方案按功能拆分多个中介者使用层次化中介者结构问题2同事类仍然直接引用彼此症状虽然引入了中介者但某些同事类还是直接调用其他同事类的方法解决方案严格通过中介者进行所有通信在代码审查中检查直接引用问题3中介者引入性能瓶颈症状系统响应变慢跟踪发现中介者是瓶颈解决方案考虑异步消息传递对高频交互使用批处理5.3 与其他模式的关系与观察者模式经常一起使用中介者可以作为观察者模式中的主题区别观察者模式侧重一对多通知中介者模式侧重对象间交互的封装与门面模式都简化了对象间的交互区别门面模式为子系统提供简化接口中介者模式协调平等对象间的交互与命令模式可以组合使用将请求封装为命令对象由中介者转发中介者模式更关注交互结构命令模式更关注请求的封装6. 现代框架中的中介者模式实现6.1 Redux中的StoreRedux的Store本质上是一个中介者协调Action、Reducer和View之间的交互// Redux中介者模式的体现 const store createStore(reducer); // View组件同事类订阅状态变化 store.subscribe(() { const state store.getState(); // 更新UI }); // Action创建函数同事类dispatch动作 function addTodo(text) { return { type: ADD_TODO, text }; } // 触发动作通过中介者store转发 store.dispatch(addTodo(Learn mediator pattern));6.2 Vue的Event BusVue中常用的Event Bus是中介者模式的轻量级实现// 创建事件总线中介者 const EventBus new Vue(); // 组件A同事类 EventBus.$emit(message, Hello from A); // 组件B同事类 EventBus.$on(message, (msg) { console.log(B received: ${msg}); });6.3 Android中的LiveDataAndroid架构组件中的LiveData也采用了中介者思想class MyViewModel : ViewModel() { val data MutableLiveDataString() } // Activity观察LiveData通过中介者 viewModel.data.observe(this, Observer { value - // 更新UI }) // Fragment修改数据通过中介者 viewModel.data.value New value7. 性能优化与高级用法7.1 异步中介者实现对于高并发场景可以实现异步中介者public class AsyncMediator implements Mediator { private final Executor executor; private final ListColleague colleagues new CopyOnWriteArrayList(); public AsyncMediator(Executor executor) { this.executor executor; } public void addColleague(Colleague colleague) { colleagues.add(colleague); } Override public void notify(Colleague sender, String event) { executor.execute(() - { for (Colleague colleague : colleagues) { if (colleague ! sender) { colleague.receive(event); } } }); } }7.2 中介者链模式对于复杂系统可以使用多个中介者形成处理链class ChainMediator: def __init__(self): self.mediators [] def add_mediator(self, mediator): self.mediators.append(mediator) def notify(self, sender, event): for mediator in self.mediators: if mediator.can_handle(event): mediator.notify(sender, event) break class LoggingMediator: def can_handle(self, event): return event.type LOG def notify(self, sender, event): print(f[LOG] {event.message}) class AlertMediator: def can_handle(self, event): return event.type ALERT def notify(self, sender, event): show_alert(event.message)7.3 中介者模式的分布式扩展在微服务架构中可以使用消息队列作为分布式中介者// 使用RabbitMQ作为分布式中介者 Configuration public class RabbitConfig { Bean public TopicExchange mediatorExchange() { return new TopicExchange(mediator.exchange); } } Service public class MessageSender { Autowired private RabbitTemplate rabbitTemplate; public void sendEvent(String routingKey, Object event) { rabbitTemplate.convertAndSend(mediator.exchange, routingKey, event); } } Service public class MessageReceiver { RabbitListener(bindings QueueBinding( value Queue(value serviceA.queue), exchange Exchange(value mediator.exchange), key event.serviceA )) public void handleEvent(Event event) { // 处理事件 } }8. 测试中介者模式实现8.1 单元测试策略测试中介者模式时需要考虑两方面测试同事类是否正确使用中介者测试中介者是否正确转发消息示例测试用例// 测试中介者 describe(ChatRoomMediator, () { let mediator: ChatRoomMediator; let user1: User; let user2: User; beforeEach(() { mediator new ChatRoomMediator(); user1 new User(Alice, mediator); user2 new User(Bob, mediator); mediator.addUser(user1); mediator.addUser(user2); }); it(should broadcast messages to all users except sender, () { const spy jest.spyOn(user2, receive); user1.send(Hello); expect(spy).toHaveBeenCalledWith(Hello); }); it(should not send message back to sender, () { const spy jest.spyOn(user1, receive); user1.send(Hello); expect(spy).not.toHaveBeenCalled(); }); }); // 测试同事类 describe(User, () { it(should send messages through mediator, () { const mockMediator { notify: jest.fn() }; const user new User(Alice, mockMediator as unknown as Mediator); user.send(Hello); expect(mockMediator.notify).toHaveBeenCalledWith(user, Hello); }); });8.2 集成测试考虑在集成测试中需要验证整个交互流程是否符合预期多个同事类通过中介者的协作是否正确异常情况下的处理机制public class MediatorIntegrationTest { Test public void testComponentInteractionThroughMediator() { // 创建中介者和同事对象 UIMediator mediator new UIMediator(); Button button new Button(mediator); TextField textField new TextField(mediator); mediator.registerComponent(button); mediator.registerComponent(textField); // 模拟用户操作 button.click(); // 验证交互结果 assertFalse(textField.isEnabled()); } }8.3 性能测试要点中介者模式可能引入的性能问题包括中介者成为单点瓶颈高频消息传递的开销内存占用问题测试建议测量消息传递的延迟在不同负载下测试吞吐量监控中介者的内存使用情况# 简单的性能测试示例 import time def test_mediator_performance(): mediator PerformanceMediator() colleagues [PerformanceColleague(mediator) for _ in range(1000)] start time.time() for _ in range(10000): colleagues[0].send(test message) duration time.time() - start print(fProcessed 10000 messages in {duration:.2f} seconds) print(fThroughput: {10000/duration:.2f} msg/sec)
阅读完成 · 觉得有帮助?