视频链接:https://v.youku.com/v_show/id_XNDYzMTg4NjQ1Ng==.html
观察者模式
定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式。
通过一个高温预警系统来分析什么是观察者模式:
具体的UML图如下:
从上面可以看出,一个观察者模式需要主题、观察者、具体主题、具体观察者。
(1)Subject:抽象主题,他把所有观察者对象保存在一个集合里,可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。意思就是明星把所有的粉丝都保存在一个账号里面,粉丝数量不限,可以新增粉丝也可以拉黑粉丝。
(2)ConcreteSubject:具体主题,该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。意思是我们的明星一有动态,就会把消息给粉丝。
(3)Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。这就是我们所有粉丝的抽象。
(4)ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。具体每一个粉丝。
1. 主题Subject
首先定义一个观察者数组,并实现增、删及通知操作。它的职责很简单,就是定义谁能观察,谁不能观察,用Vector是线程同步的,比较安全,也可以使用ArrayList,是线程异步的,但不安全。
public class Subject { //观察者数组 private Vector<Observer> oVector = new Vector<>(); //增加一个观察者 public void addObserver(Observer observer) { this.oVector.add(observer); } //删除一个观察者 public void RemoveObserver(Observer observer) { this.oVector.remove(observer); } //通知所有观察者 public void notifyAll() { for(Observer observer : this.oVector) { observer.update(); } } }
2. 抽象观察者Observer
观察者一般是一个接口,每一个实现该接口的实现类都是具体观察者。
public interface Observer { //更新 public void update(); }
3. 具体主题
继承Subject类,在这里实现具体业务,在具体项目中,该类会有很多变种。
public class ConcreteSubject extends Subject { //具体业务 public void doSomething() { //... super.notifyObserver(); } }
4. 具体观察者
实现Observer接口。
public class ConcreteObserver implements Observer { @Override public void update() { System.out.println("收到消息,进行处理"); } }
二、观察者模式的应用
1. 何时使用
- 一个对象状态改变,所有的依赖对象都将得到通知
2. 方法
- 使用面向对象技术
3. 优点
- 观察者和被观察者是抽象耦合的
- 建立了一套触发机制
4. 缺点
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
- 如果观察者和观察目标间有循环依赖,可能导致系统崩溃
- 没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的
5. 使用场景
- 关联行为场景
- 事件多级触发场景
- 跨系统的消息变换场景,如消息队列的处理机制
6. 应用实例
- 手机丢了,委托别人给其他人发消息通知
- 通知老师/老板来了
- 拍卖,拍卖师观察最高标价,然后通知给其它竞价者竞价
- 在一个目录下建立一个文件,会同时通知目录管理器增加目录,并通知磁盘减少空间,文件是被观察者,目录管理器和磁盘管理器是观察者
- 猫叫了一声,吓着了老鼠,也惊到了主人,猫是被观察者,老鼠和人是观察者
7. 注意事项
- 避免循环引用
- 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式