主要解决将一个对象的状态改变通知给其余对象的问题。java
观察者模式是一种行为设计模式,容许你定义一种订阅机制,可在对象事件发生时通知多个 “观察” 该对象的其余对象。git
如今大部分快递都不会交付到手上了,除非咱们特地选了上门服务。github
通常都是买完两三天,收到条短信:您好,您的快递已到蜂站,请凭取件码K16888取件,取件时间09:30-21:00,请及时取件。express
刚看完短信,APP也跳出一则通知:您的快递已被蜂站签收,请及时取件。设计模式
今天,就以快递到达,同时收到APP和短信通知为例,介绍一下观察者模式。架构
observer-pattern └─ src ├─ main │ └─ java │ └─ org.design.pattern.observer │ ├─ model │ │ ├─ ExpressPackage.java │ │ ├─ Courier.java │ │ └─ User.java │ ├─ subscriber │ │ ├─ ExpressEventSubscriber.java │ │ └─ impl │ │ ├─ AppExpressEventListener.java │ │ └─ SmsExpressEventSubscriber.java │ ├─ publisher │ │ └─ ExpressEventPublisher.java │ └─ service │ ├─ ExpressService.java │ └─ impl │ └─ ExpressServiceImpl.java └─ test └─ java └─ org.design.pattern.observer.test └─ ExpressEventTest.java
快递实体类app
/** * 快递 */ @Getter @Setter @AllArgsConstructor public class Express { /** * 快递id */ private String id; /** * 收件人名称 */ private String recipientName; /** * 收件人打电话 */ private String recipientPhone; /** * 收件人地址 */ private String recipientAddress; }
快递事件发布者ide
/** * 快递事件发布者 */ public class ExpressEventPublisher { /** * 快递事件订阅者列表 */ private List<ExpressEventSubscriber> subscriberList = new ArrayList<>(); /** * 订阅快递事件 * * @param expressEventSubscriber 订阅者 */ public void subscribe(ExpressEventSubscriber expressEventSubscriber) { subscriberList.add(expressEventSubscriber); } /** * 取消订阅快递事件 * * @param expressEventSubscriber 订阅者 */ public void unsubscribe(ExpressEventSubscriber expressEventSubscriber) { subscriberList.remove(expressEventSubscriber); } /** * 通知订阅者快递到达 * * @param express 快递 */ public void notifySubscribersArrive(Express express) { subscriberList.forEach(expressEventSubscriber -> expressEventSubscriber.arrive(express)); } }
快递事件订阅者接口测试
/** * 快递事件订阅者接口 */ public interface ExpressEventSubscriber { /** * 快递到达 * * @param express 快递 */ void arrive(Express express); }
App-快递事件订阅者优化
/** * App-快递事件订阅者 */ @Slf4j public class AppExpressEventListener implements ExpressEventSubscriber { /** * 快递到达 * * @param express 快递 */ @Override public void arrive(Express express) { log.info("App 通知:您的包裹{}已达到蜂站!", express.getId()); } }
短信-快递事件订阅者
/** * 短信-快递事件订阅者 */ @Slf4j public class SmsExpressEventSubscriber implements ExpressEventSubscriber { /** * 快递到达 * * @param express 快递 */ @Override public void arrive(Express express) { log.info("短信通知:您的包裹{}已达到蜂站!", express.getId()); } }
快递服务接口
/** * 快递服务接口 */ public interface ExpressService { /** * 快递已到达 * * @param express 快递 */ void arrive(Express express); }
快递服务实现类
/** * 快递服务实现类 */ @Slf4j public class ExpressServiceImpl implements ExpressService { /** * 快递事件发布者 */ private final ExpressEventPublisher expressEventPublisher; /** * 构造方法 * * @param expressEventPublisher 快递事件发布者 */ public ExpressServiceImpl(ExpressEventPublisher expressEventPublisher) { this.expressEventPublisher = expressEventPublisher; } /** * 快递到达 * * @param express 快递 */ @Override public void arrive(Express express) { log.info("{}的快递已到达蜂站!", express.getRecipientName()); expressEventPublisher.notifySubscribersArrive(express); } }
/** * 快递事件测试类 */ public class ExpressEventTest { @Test public void test() { // 快递初始化 Express express = new Express("1", "yiyufxst", "13245678910", "xx路"); // 订阅者初始化 ExpressEventSubscriber appExpressEventListener = new AppExpressEventListener(); ExpressEventSubscriber smsExpressEventSubscriber = new SmsExpressEventSubscriber(); // 发布者初始化 ExpressEventPublisher expressEventPublisher = new ExpressEventPublisher(); // 订阅快递事件 expressEventPublisher.subscribe(appExpressEventListener); expressEventPublisher.subscribe(smsExpressEventSubscriber); // 快递服务类初始化 ExpressService expressService = new ExpressServiceImpl(expressEventPublisher); // 快递到达 expressService.arrive(express); // App取消订阅快递事件 expressEventPublisher.unsubscribe(appExpressEventListener); // 模拟新快递 express.setId("2"); // 快递到达 expressService.arrive(express); } }
14:50:01.090 [main] INFO o.d.p.o.s.impl.ExpressServiceImpl - yiyufxst的快递已到达蜂站! 14:50:01.093 [main] INFO o.d.p.o.s.i.AppExpressEventListener - App 通知:您的包裹1已达到蜂站! 14:50:01.093 [main] INFO o.d.p.o.s.i.SmsExpressEventSubscriber - 短信通知:您的包裹1已达到蜂站! 14:50:01.093 [main] INFO o.d.p.o.s.impl.ExpressServiceImpl - yiyufxst的快递已到达蜂站! 14:50:01.093 [main] INFO o.d.p.o.s.i.SmsExpressEventSubscriber - 短信通知:您的包裹2已达到蜂站! Process finished with exit code 0
发布者(Publisher)会对其余对象发送值得关注的事件。事件会在发布者自身状态改变或执行特定行为后发生。发布者中包含一个容许新订阅者加入或当前订阅者离开列表的订阅架构。
当新事件发生时,发送者会便利订阅者列表并调用每一个订阅者对象的通知方法。
具体订阅者(Concrete Subscribers)能够执行一些操做来回应发布者的通知。全部订阅者类实现了一样的接口,所以发布者无需与具体类耦合。
订阅者一般须要一些上下文信息来正确地处理更新消息。所以发布者会将一些上下文数据做为通知方法的参数进行传递。发布者也可将自身做为参数传递,使订阅者直接获取所需的数据。
设计模式并不难学,其自己就是多年经验提炼出的开发指导思想,关键在于多加练习,带着使用设计模式的思想去优化代码,就能构建出更合理的代码。
源码地址:https://github.com/yiyufxst/design-pattern-java
参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei/itstack-demo-design
深刻设计模式:https://refactoringguru.cn/design-patterns/catalog