一、中介者模式介绍 1. 解决的问题 主要解决当对象与对象之间存在大量关联关系时,若一个对象发生改变,要跟踪与之相关的对象,同时做出相应处理的问题。
2. 定义 中介者模式 是一种行为设计模式,能减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互,迫使它们通过一个中介者对象进行合作。
3. 应用场景
当一些对象与其他对象紧密耦合以至于难以对其进行修改时,可使用中介者模式。
当组件因过于依赖其他组件而无法在不同应用中复用时,可使用中介者模式。
为了在不同情景下复用一些基本行为,导致需要被迫创建大量组件子类时,可使用终结者模式。
二、中介者模式优缺点 1. 优点
单一职责原则:可以将多个组件间的交流抽取到同一位置,使其更易于理解和维护。
开闭原则:无需修改实际组件就能增加新的中介者。
可以减轻应用中多个组件的耦合情况。
可以更方便地复用各个组件。
2. 缺点
三、中介者模式应用实例:菜鸟驿站 1. 实例场景 相信大家平时快递来不及拿的话,大部分时候都会选择让快递小哥将快递放到菜鸟驿站,我们在放学/下班后再去菜鸟驿站拿自己的快递。同时,我们如果有快递需要寄出,也是现在菜鸟驿站填写寄件单,然后快递小哥从菜鸟驿站拿到快递,发货。
其实在这里,菜鸟驿站就是一个中介者,承担着快递小哥和我们之间的重要交流枢纽。
今天,我们就以菜鸟驿站为例,介绍一下中介者模式。
2. 中介者模式实现 2.1 工程结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 mediator-pattern └─ src ├─ main │ └─ java │ └─ org.design.pattern.mediator │ ├─ model │ │ ├─ ExpressPackage.java │ │ ├─ Courier.java │ │ └─ User.java │ └─ service │ ├─ CourierStation.java │ └─ impl │ └─ CaiNiaoCourierStation.java └─ test └─ java └─ org.design.pattern.mediator └─ CourierStationTest.java
2.2 代码实现 2.2.1 实体类 快递包裹
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Getter @Setter @AllArgsConstructor public class ExpressPackage { private String id; private String name; private String consigneePhoneNumber; private CourierStation sendCourierStation; private CourierStation receiveCourierStation; }
快递员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 @Slf4j @Getter @Setter @AllArgsConstructor public class Courier { private String id; private String name; public void sendExpressPackage (ExpressPackage expressPackage) { expressPackage.getReceiveCourierStation().receiveExpressPackage(expressPackage); } public void receiveExpressPackage (ExpressPackage expressPackage) { log.info( "The courier {} has arrived in the hands of the express package {}, and it will be sent to you immediately." , this .getName(), expressPackage.getName() ); } }
用户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 @Getter @Setter @AllArgsConstructor public class User { private String id; private String name; private String phone; public void sendExpressPackage (ExpressPackage expressPackage) { expressPackage.getSendCourierStation().sendExpressPackage(expressPackage); } }
2.2.2 服务类 快递站中介者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public interface CourierStation { void receiveExpressPackage (ExpressPackage expressPackage) ; void sendExpressPackage (ExpressPackage expressPackage) ; }
菜鸟驿站
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 @Slf4j @Getter @Setter public class CaiNiaoCourierStation implements org .design.pattern.mediator.service.CourierStation { private List<Courier> courierList; @Override public void receiveExpressPackage (ExpressPackage expressPackage) { log.info( "The package {} has arrived at the cai niao courier station, please pick it up as soon as possible." , expressPackage.getName() ); } @Override public void sendExpressPackage (ExpressPackage expressPackage) { Optional<Courier> courierOptional = courierList.stream().findAny(); if (courierOptional.isPresent()) { Courier courier = courierOptional.get(); courier.receiveExpressPackage(expressPackage); } } }
2.3 测试验证 2.3.1 测试验证类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class CourierStationTest { @Test public void testReceiveExpressPackage () { Courier courier = new Courier ("1" , "快递小哥" ); CaiNiaoCourierStation courierStation = new CaiNiaoCourierStation (); courierStation.setCourierList(Collections.singletonList(courier)); ExpressPackage expressPackage = new ExpressPackage ( "1" , "PS5" , "13245678910" , null , courierStation ); courier.sendExpressPackage(expressPackage); } @Test public void testSendExpressPackage () { User user = new User ("1" , "张三" , "13245678910" ); Courier courier = new Courier ("1" , "快递小哥" ); CaiNiaoCourierStation courierStation = new CaiNiaoCourierStation (); courierStation.setCourierList(Collections.singletonList(courier)); ExpressPackage expressPackage = new ExpressPackage ( "1" , "Kindle" , "13245678910" , courierStation, null ); user.sendExpressPackage(expressPackage); } }
2.3.2 测试结果 1 2 3 4 22 :19 :52.811 [main] INFO o.d.p.m.s.impl.CaiNiaoCourierStation - The package PS5 has arrived at the cai niao courier station, please pick it up as soon as possible.22 :19 :52.814 [main] INFO o.d.pattern.mediator.model.Courier - The courier 快递小哥 has arrived in the hands of the express package Kindle, and it will be sent to you immediately.Process finished with exit code 0
四、中介者模式结构
组件 (Component)是包含各种业务逻辑的类。每个组件都有一个指向中介者的引用,该引用被声明为中介者接口类型。组件不知道中介者实际所属的类,因此可通过连接到不同的中介者使其能在其他程序中复用。
中介者 (Mediator)接口声明了与组件交流的方法,但通常仅包含一个通知方法。组件可将任意上下文(包括自身对象)作为该方法的参数,只有这样接收组件和发送者类才不会耦合。
具体中介者 (Concrete Mediator)封装了多种组件间的关系。具体中介者通常会保存所有组件的引用并对其进行管理,甚至有时会对其生命周期进行管理。
组件并不知道其他组件的情况。如果组件内发生了重要事件,它只能通知中介者。中介者收到通知后能轻易确定发送者,这就足以判断下一步要触发的组件。
对于组件来说,中介者看上去完全就是一个黑箱。发送者不知道最终会由谁来处理自身的请求,接收者也不知道请求究竟来自于谁。
设计模式并不难学,其本身就是多年经验提炼出的开发指导思想,关键在于多加练习,带着使用设计模式的思想去优化代码,就能构建出更合理的代码。
源码地址:https://github.com/yiyufxst/design-pattern-java
参考资料: 小博哥重学设计模式:https://github.com/fuzhengwei/itstack-demo-design 深入设计模式:https://refactoringguru.cn/design-patterns/catalog