观察者模式(Observer Pattern):定义对象间一 种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。
观察者模式的别名包括发布-订阅(Publish/Subscribe) 模式、模型-视图(Model/View) 模式、源-监听器(Source/Listener)模式或从属者(Dependents) 模式。
原理类图
四个角色
- 抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
- 抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
- 具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
- 具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
应用场景
Zookeeper事件通知节点、消息订阅通知、安卓开发事件注册、分布式配置中心
-
jdk 中的观察者模式,在 JDK 的 java.util 包中,提供了 Observable 类以及 Observer 接口,它们构成了 JDK 对观察者模式的支持。但是在Java9被弃用了。
-
spring中的观察者模式:
- 事件:ApplicationEvent 是所有事件对象的父类。ApplicationEvent 继承自 jdk 的 EventObject, 所有的事件都需要继承 ApplicationEvent, 并且通过 source 得到事件源。
Spring 也为我们提供了很多内置事件,ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、ContextClosedEvent、RequestHandledEvent。 - 事件监听:ApplicationListener,也就是观察者,继承自 jdk 的 EventListener,该类中只有一个方法 onApplicationEvent。当监听的事件发生后该方法会被执行。
- 事件源:ApplicationContext,ApplicationContext 是 Spring 中的核心容器,在事件监听中 ApplicationContext 可以作为事件的发布者,也就是事件源。因为 ApplicationContext 继承自 ApplicationEventPublisher。在 ApplicationEventPublisher 中定义了事件
- 发布的方法:publishEvent(Object event)
事件管理:ApplicationEventMulticaster,用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的,它的作用是把 Applicationcontext 发布的 Event 广播给它的监听器列表。
- 事件:ApplicationEvent 是所有事件对象的父类。ApplicationEvent 继承自 jdk 的 EventObject, 所有的事件都需要继承 ApplicationEvent, 并且通过 source 得到事件源。
-
对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变。
如,用于支付成功一个订单时,会出发一些操作:
- 记录文本日志
- 发送短信优惠券
- 赠送活动优惠券
并且以后还会扩展一些其他的操作,这时比较适合使用观察者模式。 -
对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。
-
Swing中的事件处理(Swing组件是被观察者,每个实现监听器的类就是观察者)
优缺点
优点
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系
- 目标与观察者之间建立了一套触发机制
- 支持广播通信
- 符合“开闭原则”的要求
缺点
- 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用
- 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率
简单观察者代码实现
观察者模式–抽象主题者(通知者接口)
public interface Subject {
//增加
public void attach(Observer observer);
//删除
public void detach(Observer observer);
//通知
public void notifyObservers();
//状态
public void setAction(String action);
public String getAction();
}
具体被观察者角色
public class Secretary implements Subject {
//同事列表
private List<Observer> observers = new LinkedList<>();
private String action;
@Override
public void attach(Observer observer) {
observers.add(observer);
}
@Override
public void detach(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
@Override
public void setAction(String action) {
this.action = action;
}
@Override
public String getAction() {
return action;
}
}
抽象观察者角色
public abstract class Observer {
protected String name;
protected Subject subject;
public Observer(String name, Subject subject) {
this.name = name;
this.subject = subject;
}
public abstract void update();
}
具体观察者角色
public class StockObserver extends Observer {
public StockObserver(String name, Subject subject) {
super(name, subject);
}
@Override
public void update() {
System.out.println(subject.getAction() + "::" + name + "关闭股票行情,继续工作");
}
}
测试类
public class Test {
public static void main(String[] args) {
//前台为通知者
Secretary secretary = new Secretary();
StockObserver observer = new StockObserver("kaico", secretary);
//前台通知,注册
secretary.attach(observer);
//adam没被前台通知到,所以被老板抓了个现行
// secretary.detach(observer);
//老板回来了
secretary.setAction("小心!Boss回来了!");
//发通知
secretary.notifyObservers();
}
}
Spring中观察者代码实现
Springboot项目获取:ApplicationContext
- @Autowired(@Resouce)注入
- 实现ApplicationContextAware接口(推荐)
- 构造器方法注入
使用springboot实现
底层也是使用观察者模式实现
编写被观察者,订单创建
public class OrderCreateEvent extends ApplicationEvent {
private JSONObject jsonObject;
public OrderCreateEvent(Object source, JSONObject jsonObject) {
super(source);
this.jsonObject = jsonObject;
}
public JSONObject getJsonObject() {
return jsonObject;
}
public void setJsonObject(JSONObject jsonObject) {
this.jsonObject = jsonObject;
}
}
邮件服务,监听订单创建(观察者)
@Component
public class EmailListener implements ApplicationListener<OrderCreateEvent> {
@Override
@Async
public void onApplicationEvent(OrderCreateEvent event) {
System.out.println(Thread.currentThread().getName()+"发送邮件内容:" + event.getJsonObject().toJSONString());
}
}
短信服务,监听订单创建
@Component
public class SmsListener implements ApplicationListener<OrderCreateEvent> {
@Override
@Async
public void onApplicationEvent(OrderCreateEvent event) {
System.out.println(Thread.currentThread().getName() + "发送短信内容:" + event.getJsonObject().toJSONString());
}
}
测试的controller
@RestController
public class TestController {
@Autowired
private ApplicationContext applicationContext;
@RequestMapping("/addOrder")
public String addOrder() {
System.out.println("创建订单...");
// 3.组装消息内容
JSONObject jsonObject = new JSONObject();
jsonObject.put("email", "kaico@qq.com");
jsonObject.put("phone", "18522233222");
jsonObject.put("text", "恭喜您以1399.00元购买永久会员.");
OrderCreateEvent orderCreateEvent = new OrderCreateEvent(this, jsonObject);
applicationContext.publishEvent(orderCreateEvent);
return "success";
}
}