观察者模式(Observer Design Pattern)也被称为发布订阅模式。它的定义是这样的:在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。

应用

假设我们在开发一个 P2P 投资理财系统,用户注册成功之后,我们会给用户发放投资体验金。代码实现大致是下面这个样子的:

  1. public class UserController {
  2. private UserService userService; // 依赖注入
  3. private PromotionService promotionService; // 依赖注入
  4. public Long register(String telephone, String password) {
  5. //省略输入参数的校验代码
  6. //省略userService.register()异常的try-catch代码
  7. long userId = userService.register(telephone, password);
  8. promotionService.issueNewUserExperienceCash(userId);
  9. return userId;
  10. }
  11. }

虽然注册接口做了两件事情,注册和发放体验金,违反单一职责原则,但是,如果没有扩展和修改的需求,现在的代码实现是可以接受的。如果非得用观察者模式,就需要引入更多的类和更加复杂的代码结构,反倒是一种过度设计。
相反,如果需求频繁变动,比如,用户注册成功之后,不再发放体验金,而是改为发放优惠券,并且还要给用户发送一封“欢迎注册成功”的站内信。这种情况下,我们就需要频繁地修改 register() 函数中的代码,违反开闭原则。而且,如果注册成功之后需要执行的后续操作越来越多,那 register() 函数的逻辑会变得越来越复杂,也就影响到代码的可读性和可维护性。
这个时候,观察者模式就能派上用场了。利用观察者模式,我对上面的代码进行了重构。重构之后的代码如下所示:

  1. public interface RegObserver {
  2. void handleRegSuccess(long userId);
  3. }
  4. public class RegPromotionObserver implements RegObserver {
  5. private PromotionService promotionService; // 依赖注入
  6. @Override
  7. public void handleRegSuccess(long userId) {
  8. promotionService.issueNewUserExperienceCash(userId);
  9. }
  10. }
  11. public class RegNotificationObserver implements RegObserver {
  12. private NotificationService notificationService;
  13. @Override
  14. public void handleRegSuccess(long userId) {
  15. notificationService.sendInboxMessage(userId, "Welcome...");
  16. }
  17. }
  18. public class UserController {
  19. private UserService userService; // 依赖注入
  20. private List<RegObserver> regObservers = new ArrayList<>();
  21. // 一次性设置好,之后也不可能动态的修改
  22. public void setRegObservers(List<RegObserver> observers) {
  23. regObservers.addAll(observers);
  24. }
  25. public Long register(String telephone, String password) {
  26. //省略输入参数的校验代码
  27. //省略userService.register()异常的try-catch代码
  28. long userId = userService.register(telephone, password);
  29. for (RegObserver observer : regObservers) {
  30. observer.handleRegSuccess(userId);
  31. }
  32. return userId;
  33. }
  34. }

总结

设计模式要干的事情就是解耦,创建型模式是将创建和使用代码解耦,结构型模式是将不同功能代码解耦,行为型模式是将不同的行为代码解耦,具体到观察者模式,它将观察者和被观察者代码解耦。借助设计模式,我们利用更好的代码结构,将一大坨代码拆分成职责更单一的小类,让其满足开闭原则、高内聚低耦合等特性,以此来控制和应对代码的复杂性,提高代码的可扩展性。
观察者模式的应用场景非常广泛,小到代码层面的解耦,大到架构层面的系统解耦,再或者一些产品的设计思路,都有这种模式的影子,比如,邮件订阅、RSS Feeds,本质上都是观察者模式。不同的应用场景和需求下,这个模式也有截然不同的实现方式,有同步阻塞的实现方式,也有异步非阻塞的实现方式;有进程内的实现方式,也有跨进程的实现方式。