文章目录
- 前言
- 一、什么是观察者模式
- 二、Java实现观察者模式
- 2.1 观察者接口
- 2.2 具体观察者
- 2.3 基础发布者
- 2.4 具体发布者
- 2.5 消息发送
- 三、Spring实现观察者模式
- 3.1 定义事件类
- 3.2 具体观察者
- 3.3 具体发布者
- 3.4 消息发送
- 总结
前言
随着系统的复杂度变高,我们就会采取各种各样的优化手段来进行解耦,降低系统的复杂度,其中设计模式是古人经验的一种设计总结,场景一:发送消息的时候,需要采取不同的消息发送渠道,一次发送一个或者多个渠道,这种不确定的变化,我们就可以采用观察者模式来进行解耦,当一个对象状态发生改变时,其他依赖对象的状态也随之变更,这是观察者模式的核心。
注:本篇文章纯干货,采用Java的设计模式以及Spring设计模式实现,另外设计编码了交互页面,能够更直观体验观察者模式之美
一、什么是观察者模式
观察者模式是一种行为设计模式,类似于【发布订阅】,定义对象间的一种【一对多】的依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
二、Java实现观察者模式
2.1 观察者接口
/*** 监听(观察者)接口* @author: DT辰白 Created by 2024/5/3 8:09*/
public interface EventListener {void update(String message);}
2.2 具体观察者
/*** 具体观察者* @author: DT辰白 Created by 2024/4/28 20:12*/
@Slf4j
@Service
public class EmailListener implements EventListener {@Overridepublic void update(String message) {log.info("邮箱:QQ邮箱发送消息,消息内容【{}】",message);}
}
/*** 具体观察者* @author: DT辰白 Created by 2024/4/28 20:14*/
@Slf4j
@Service
public class SmsListener implements EventListener {@Overridepublic void update(String message) {log.info("短信:短信发送消息,消息内容【{}】", message);}
}
2.3 基础发布者
这里我们使用了@Autowired注入,其实默认的实现类【EmailListener 、SmsListener】已经注入了,你也可以将List 做成一个普通的List集合,然后在使用的时候,将订阅对象添加到该List集合。
/*** @author: DT辰白 Created by 2024/4/28 20:17*/
@Component
public class EventManager {@Autowiredprivate List<EventListener> listeners;/*** 订阅* @param eventListeners*/public void subscribe(EventListener... eventListeners) {for (EventListener eventListener : eventListeners) {// 防止重复注入if (!listeners.contains(eventListener)) {this.listeners.add(eventListener);}}}/*** 取消订阅* @param eventListeners*/public void unsubscribe(EventListener... eventListeners) {for (EventListener eventListener : eventListeners) {listeners.remove(eventListener);}}/*** 通知* @param message*/public void notify(String message) {for (EventListener eventListener : listeners) {eventListener.update(message);}}
}
2.4 具体发布者
这里我们直接继承父类,可以通过子类调用父类的方法,我们也可以将此处做成一个抽象接口对外提供,具体方法有很多,根据自己的业务需求即可。
/*** 具体发布者* @author: DT辰白 Created by 2024/4/28 20:25*/
@Service
public class MessagePublisher extends EventManager {public void publishMessage(String message) {notify(message);}}
2.5 消息发送
@PostMapping(value = "/publishMessage")
@ApiOperation(value = "观察者模式【java】->发送消息")
public ResultUtil publishMessage(String message) {// 订阅(默认订阅全部)// messagePublisher.subscribe(emailListener,smsListener);// 取消订阅// messagePublisher.unsubscribe(smsListener);// 发布messagePublisher.publishMessage(message);return ResultUtil.success();
}
2024-05-03 08:25:17.049 INFO 12896 --- [nio-9091-exec-4] c.d.m.d.pattern.observer.EmailListener : 邮箱:QQ邮箱发送消息,消息内容【我是一条鱼】
2024-05-03 08:25:17.049 INFO 12896 --- [nio-9091-exec-4] c.d.m.d.pattern.observer.SmsListener : 短信:短信发送消息,消息内容【我是一条鱼】
三、Spring实现观察者模式
3.1 定义事件类
/*** 定义事件类* @author: DT辰白 Created by 2024/4/28 21:33*/
public class NotificationEvent extends ApplicationEvent {private String message;public NotificationEvent(Object source, String message) {super(source);this.message = message;}public String getMessage() {return message;}
}
3.2 具体观察者
/*** @author: DT辰白 Created by 2024/4/28 21:34*/
@Slf4j
@Component
public class EmailNotificationListener {@EventListenerpublic void onApplicationEvent(NotificationEvent event) {// 发送邮件通知log.info("邮箱:QQ邮箱发送消息,消息内容【{}】",event.getMessage());}
}
/*** @author: DT辰白 Created by 2024/4/28 21:34*/
@Slf4j
@Component
public class SMSNotificationListener {@EventListenerpublic void onApplicationEvent(NotificationEvent event) {// 发送短信通知log.info("短信:短信发送消息,消息内容【{}】", event.getMessage());}
}
3.3 具体发布者
/*** 发布者接口* @author: DT辰白 Created by 2024/4/28 21:35*/
public interface NotificationService {void notifyUsers(String message);
}
/*** 事件发布者* @author: DT辰白 Created by 2024/4/28 21:35*/
@Service
public class NotificationPublisher implements NotificationService {@Autowiredprivate ApplicationEventPublisher publisher;@Overridepublic void notifyUsers(String message) {publisher.publishEvent(new NotificationEvent(this, message));}
}
3.4 消息发送
@PostMapping(value = "/publishMsg")
@ApiOperation(value = "观察者模式【spring】->发送消息")
public ResultUtil publishMsg(String message) {notificationService.notifyUsers(message);return ResultUtil.success();
}
2024-05-03 10:39:14.302 INFO 12680 --- [nio-9091-exec-3] c.d.m.d.p.o.s.EmailNotificationListener : 邮箱:QQ邮箱发送消息,消息内容【我是一条鱼】
2024-05-03 10:39:14.302 INFO 12680 --- [nio-9091-exec-3] c.d.m.d.p.o.s.SMSNotificationListener : 短信:短信发送消息,消息内容【我是一条鱼】
以上方式为同步发送,如果不需要保证数据一致性,只要其中一个渠道消息发送成功即可,我们可以采用异步的方式发送,这样就不会影响其它正常的渠道发送,当然也是我们项目中常用的方式,发送失败的渠道,采用补偿机制或者人工介入重新发送即可。
最后,为了更直观的体验观察者模式,我们设计了一个交互页面:
总结
观察者模式是一种行为设计模式,定义了一种一对多的依赖关系,当一个对象状态发生变化时,所有依赖它的对象都会得到通知并自动更新。Spring中的事件驱动模型就是观察者模式的典型应用。