设计模式 - 观察者模式
本文转载自屈定’s Blog
观察者模式
观察者模式描述的是一种一对多的关系,这里的一可能是某个状态发生变化,也可能是某一个事件产生.举个例子,针对订单付款,这一事件产生后可能需要经过很多个处理步骤,比如积分,入库,消费排行榜之类的操作,这些操作之间并没有任何关联性甚至可以并行处理,那么就可以理解为订单付款与处理步骤之间的一对多关系.
还有一个特点就是单向依赖,处理步骤对于订单付款是单向依赖的,比如有订单付款,才能有处理步骤.但是反之就不依赖,订单付款对于有没有处理步骤是不关心的,这一点在下文实战中会详细讲解.
观察者模式结构
观察者模式主要结构如下:
- Subject: 负责事件产生后通知到具体观察者的角色,所谓的通知实际上是循环调用其所持有的观察者接口
- Observer: 负责对事件的处理,该接口可以很好的做到任务分离,每一个不同的任务都是其一个实现子类,互相不关心对方,很好的描述了业务上的关系.
那么本质什么?用一个Subject
来聚合所有的Observer
,那么调用者只需要关心对应的Subject
就可以.
为什么可以这样? 因为Observer
之间没有任何关系,只是单纯的做自己要做的事情,也并不需要返回值之类的东西.
观察者模式的实战案例
如笔者一开始描述的需求,再订单付款完成之后执行一些处理步骤,具体如下:
- 如果是虚拟产品订单,那么就发放虚拟产品
- 如果是会员订单那么就开通会员
- 根据付款金额增加积分
- 如果有消费排行榜活动则更新用户金额.
- …..
这种是开发中很常见的付款后一些对应的操作需求,并且随着活动之类的增加后续还很容易增加其他的处理步骤需求,对于观察者模式其符合以下两点特征:
- 订单付款完成这一事件对应对个处理步骤,典型一对多关系
- 处理步骤之间并无关联性,每一个都是独立的处理
观察者模式设计
上述用观察模式可以设计出如下结构:
OrderPaidHandlerObserver
其是观察者需要实现的接口,主要功能是判断是不是自己可以处理,可以处理的话就处理,其子类各司其职,比如IntegralOrderService
是处理积分相关的观察者,VipOrderService
则是处理会员相关的Service.
1 | public interface OrderPaidHandlerObserver { |
OrderPaidHandlerSubject
其是负责通知所有观察者的接口,实现了该接口就有了通知观察者的义务.
1 | public interface OrderPaidHandlerSubject { |
OrderCompositeService
其是OrderPaidHandlerSubject
的实现类,主要实现负责通知所有观察者的逻辑,所谓的通知本质上就是调用自己所持有的观察者对象,那么当订单付款事件产生后OrderCompositeService
只需要调用下notifyObservers()
方法就可以完成通知,完成所有的处理步骤.
1 | public class OrderCompositeService implements OrderPaidHandlerSubject { |
使用Spring管理观察者
OrderCompositeService
作为Subject来说,其持有了全部的Observer
,那么如果利用IOC把Observer
全部注入进该类中,那么当下次新增加一个Observer
实现类时就不需要改这边的任何代码,完完全全的解耦.
思路是利用IOC管理所有的观察者,当Spring容器启动完毕后获取所有的观察者,添加到对应的observers
集合中,具体做法就是让OrderCompositeService
实现ApplicationListener<ContextRefreshedEvent>
接口,Spring在启动完毕后会发出通知,在该接口中利用BeanFactoryUtils
初始化所需要的观察者集合.
1 | /** |
这样做的好处就是把观察者的实例化与Subject解耦,对于观察者只需要知道自己一旦实现了观察者接口,那么就一定会有相应的Subject通知自己就足够了.
观察者的 “感兴趣” 粒度
在观察者模式中Observer
会像Subject
注册自己,那么当Subject对应多个事件时怎么处理呢?
1.Subject管理多组Observer
在Subject
中存放着多组Observer
,当一个事件触发时只会通知其中一组.这样做法个人感觉是比较合理的.缺点是管理不方便,对于Subject
来说要管理多组,对应的removeOvserver或者addObserver就会比较麻烦了,此时可以依赖IOC等工具完成这个过程.
2.Observer多角色
这种方案下,对于一个Subject
他管理的只有一组Observer
,但是Observer
本身要承担多个责任,并且对自己不感兴趣的责任要留空方法处理.Observer
可能只对一件事情感兴趣却不得不实现一堆空方法,不符合最少知道原则.Java的AWT
就是这种设计.
3.使用弱类型参数
JDK自带的Observer
就是类似的形式,其使用Object
作为观察者参数,当接收到消息时需要用instance
判断是否是自己感兴趣的事件,然后才执行逻辑,当事件很少的话这种方式是比较合适的,事件多的话则对一堆事件要分开处理,依然很麻烦.Eclipse的SWT是这种设计.