文章目录
- 前言
- 一、什么是观察者模式
- 二、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 {
@Override
public void update(String message) {
log.info("邮箱:QQ邮箱发送消息,消息内容【{}】",message);
}
}
/**
* 具体观察者
* @author: DT辰白 Created by 2024/4/28 20:14
*/
@Slf4j
@Service
public class SmsListener implements EventListener {
@Override
public 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 {
@Autowired
private 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 {
@EventListener
public void onApplicationEvent(NotificationEvent event) {
// 发送邮件通知
log.info("邮箱:QQ邮箱发送消息,消息内容【{}】",event.getMessage());
}
}
/**
* @author: DT辰白 Created by 2024/4/28 21:34
*/
@Slf4j
@Component
public class SMSNotificationListener {
@EventListener
public 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 {
@Autowired
private ApplicationEventPublisher publisher;
@Override
public 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中的事件驱动模型就是观察者模式的典型应用。