设计模式之观察者模式
一、定义:
观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
二、观察者模式中需要如下几种角色:
1、Subject:抽象主题(抽象被观察者),主要提供对观察者对象集合的增、删和通知方法。
2、ConcreteSubject:具体主题(具体被观察者),将所有观察者放到集合里,再具体主题的内部状态发生变化时,给所有注册过的观察者发送通知。
3、Observer:抽象观察者,是观察者的抽象类,它定义了一个更新方法,使得再得到被观察者通知时,即时更新自己。
4、ConcrereObserver:具体观察者,实现抽象观察者的更新方法,更新自己。
三、观察者模式简单实现
1、故事情景:企业有一个人源库系统管理所有人员基本信息,还有一个是财务系统和钉钉,财务和钉钉都紧密和人员信息紧密挂钩,假设人源库是被观察者,财务和钉钉是观察者,当人员信息被修改时需要即时通知财务和钉钉更新。
2、观察者模式UML类图:
3、让我们来看看代码如何实现的
抽象观察者(Observer)
里面定义了一个更新的抽象方法
1 public interface IObserverService { 2 void update(PeopleEntity peopleEntity);
3}
具体观察者(ConcrereObserver)
不同观察者实现抽象方法
1 /** 2 *@author : lsy 3 *@description: 钉钉具体观察者
5 */ 6 @Service 7 public class DingDingObserverImpl implements IObserverService{ 8 @Override 9 public void update(PeopleEntity peopleEntity) { 10 System.out.println("钉钉:"+peopleEntity.toString()); 11 } 12 }
1 /** 2 *@author : lsy 3 *@description: 财务具体观察者
5 */ 6 @Service 7 public class FinanceObserverImpl implements IObserverService{ 8 @Override 9 public void update(PeopleEntity peopleEntity) { 10 System.out.println("财务系统:"+peopleEntity.toString()); 11 } 12 }
抽象被观察者(Subject)
定义了新增、移除、通知观察者的抽象方法
1 /** 2 *@author : lsy 3 *@description: 抽象被观察者 4 */ 5 public interface ISubjectService { 6 //增加观察者 7 void attach(IObserverService observerService); 8 9 //移除观察者 10 void detach(IObserverService observerService); 11 12 //通知观察者 13 void notice(PeopleEntity peopleEntity); 14 }
具体被观察者(ConcreteSubject)
创建一个用于存放观察者List集合,并实现抽象方法
1 /** 2 *@author : lsy 3 *@description: 人源库具体被观察者 5 */ 6 @Service 7 public class PeopleBasicSubjectImpl implements ISubjectService{ 8 private List<IObserverService> observerServiceList = new ArrayList<>(); 9 10 /** 11 * 增加观察者 12 * @param observerService 13 */ 14 @Override 15 public void attach(IObserverService observerService) { 16 observerServiceList.add(observerService); 17 } 18 19 /** 20 * 移除观察者 21 * @param observerService 22 */ 23 @Override 24 public void detach(IObserverService observerService) { 25 observerServiceList.remove(observerService); 26 } 27 28 /** 29 * 通知观察者 30 */ 31 @Override 32 public void notice(PeopleEntity peopleEntity) { 33 System.out.println("人源库新增:"+peopleEntity.toString()); 34 observerServiceList.forEach(observer -> observer.update(peopleEntity)); 35 } 36 }
启动类:
1 /** 2 *@author : lsy 3 *@description: 启动类 5 */ 6 @SpringBootApplication 7 public class StartClass { 8 public static void main(String[] args) { 9 PeopleEntity peopleEntity = new PeopleEntity(1, "测试", "后端", "小菜鸟"); 10 //创建两个观察者 11 IObserverService dingObserver = new DingDingObserverImpl(); 12 IObserverService financeObserver = new FinanceObserverImpl(); 13 //被观察者具体实现类 14 ISubjectService peopleBasicSubject = new PeopleBasicSubjectImpl(); 15 //添加观察者 16 peopleBasicSubject.attach(dingObserver); 17 peopleBasicSubject.attach(financeObserver); 18 //通知观察者 19 peopleBasicSubject.notice(peopleEntity); 20 21 } 22 }
控制台输出:
总结:
使用观察者模式的场景:
关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系。
事件多级触发场景。
跨系统的消息交换场景,如消息队列、事件总线的处理机制。
优点:
解除耦合,让耦合的双方都依赖于抽象,从而使得各自的变换都不会影响另一边的变换。
缺点:
在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。