写点什么

观察者模式

用户头像
Geek_571bdf
关注
发布于: 1 小时前

1. 什么是观察者模式?

2. 观察者模式有什么作用?可以实现怎样的效果?

3. 实现一个观察者模式

4. 观察者模式的不同实现:同步阻塞、异步非阻塞、进程内、跨进程


1. 什么是观察者模式?

观察者模式也叫“发布-订阅”模式。在对象之间定义一个 一对多 的依赖,当被依赖对象状态改变时,所有依赖对象会自动收到通知。

 

2. 观察者模式的实现。

事件发生所在类即被观察者,在被观察者对象中注册多个观察者。当被观察者某个方法被调用时,会依次调用注册到被观察者中的观察者的方法。// 如下所示,当请求 controller 的 register()时,会依次调用 RegObserver 的 handleRegSuccess

public interface RegObserver {  void handleRegSuccess(long userId);}public class RegPromotionObserver implements RegObserver {  private PromotionService promotionService; // 依赖注入  @Override  public void handleRegSuccess(long userId) {    promotionService.issueNewUserExperienceCash(userId);  }}public class RegNotificationObserver implements RegObserver {  private NotificationService notificationService;  @Override  public void handleRegSuccess(long userId) {    notificationService.sendInboxMessage(userId, "Welcome...");  }}
public class UserController { private UserService userService; // 依赖注入 private List<RegObserver> regObservers = new ArrayList<>(); // 一次性设置好,之后也不可能动态的修改 public void setRegObservers(List<RegObserver> observers) { regObservers.addAll(observers); } public Long register(String telephone, String password) { //省略输入参数的校验代码 //省略userService.register()异常的try-catch代码 long userId = userService.register(telephone, password); for (RegObserver observer : regObservers) { observer.handleRegSuccess(userId);}// promotionService.issueNewUserExperienceCash(userId); 不使用观察者模式。发放体验金,但当需求改变时,需要硬编码 return userId; }}
复制代码

注意,并非接口叫 Subject-Observer 才叫观察者模式。结构上属于这种形式的就是观察者模式。比如上面的 Controller 并没有 Subject 字样,但它就是被观察者,而上面这样的组织形式就是观察者模式。

 

3. 观察者模式有什么作用?可以实现怎样的效果?

效果:当被观察的某个特定被调用方法时,会依次调用事先注册好的观察者的方法。

作用:在上面代码实现中,用户注册后,我们会发放体验金、发送一封邮件。当我们要增添需求时,比如,注册时,推送用户注册信息给大数据征信系统,那么我们只需要新建一个实现 RegObserver 接口的类,并添加到 Controller 中。register()完全不用修改。

 

4. 观察者模式的不同实现:同步阻塞、异步非阻塞、进程内、跨进程

上面的实现,是进程内、同步阻塞的。即,被观察者的执行和观察者的执行是在同一个线程中被执行的。register()依次调用执行每个观察者的 handleRegSuccess(),等到都执行完成,才会返回结果给客户端。

 

如果我们希望接口响应时间尽可能短,可以改用异步非阻塞的方式。比如,我们可以将 handleRegSuccess()的执行提交到线程池中。这样 register()从 3 个 SQL 返回,缩短到 1 个 SQL 返回。另外,我们还可以基于 EventBus 来实现异步非阻塞。

 

上面都是进程内的。如果注册后,我们需要发送用户信息给大数据征信系统,而大数据征信系统是一个独立的系统,跟它交互是跨进程的。如果大数据征信系统提供了发送用户注册信息的 RPC 接口,我们可以调用 RPC 接口来发送数据。

 

当然,我们还可以基于消息队列。传统实现 观察者需要注册到被观察者中,被观察者需要依次遍历观察者来发送消息。而基于消息队列,被观察者只管发送消息到消息队列,观察者只管从消息队列中读取消息来执行相应的逻辑。被观察者完全不感知观察者,观察者也完全不感知被观察者。


用户头像

Geek_571bdf

关注

还未添加个人签名 2019.06.13 加入

还未添加个人简介

评论

发布
暂无评论
观察者模式