观察者模式概念
在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。
- 抽象被观察者角色(Subject):也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
- 抽象观察者角色(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
- 具体被观察者角色(ConcreteSubject):也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
- 具体观察者角色(ConcreteObserver):实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
//这个接口是为了提供一个统一的观察者做出相应行为的方法 public interface Observer { void update(Observable o); //观察者观察到更新操作时,进行更新 }
/* * 被观察者 * */ public class Observable { List<Observer> observers = new ArrayList<Observer>(); //用于保存观察者对象 public void addObserver(Observer o) { //添加观察者对象 observers.add(o); } public void changed() { System.out.println("我是被观察者,我已经发生变化了"); notifyObservers();//通知观察自己的所有观察者 } public void notifyObservers() { //依次通知观察者 for (Observer observer : observers) { observer.update(this); } } }
public class ConcreteObserver1 implements Observer { @Override public void update(Observable o) { System.out.println("观察者1观察到" + o.getClass().getSimpleName() + "发生变化"); System.out.println("观察者1做出相应"); } }
public class ConcreteObserver2 implements Observer { @Override public void update(Observable o) { System.out.println("观察者2观察到" + o.getClass().getSimpleName() + "发生变化"); System.out.println("观察者2做出相应"); } }
public class Client { public static void main(String[] args) throws Exception { Observable observable = new Observable(); observable.addObserver(new ConcreteObserver1()); observable.addObserver(new ConcreteObserver2()); observable.changed(); } }我是被观察者,我已经发生变化了
观察者1观察到Observable发生变化
观察者1做出相应
观察者2观察到Observable发生变化
观察者2做出相应
Java中对观察者模式的支持
在java.util包里面有一个类Observable,它实现了大部分我们需要的目标的功能;
还有一个接口Observer,它里面定义了update的方法,就是观察者的接口。
这个就更加简单了:
口诀:被观察者实现继承Observable,观察者实现Observer接口
然后有个很关键的地方:当通知变化的时候,需要调用setChange()方法!!!!
改写下上面的例子,代码如下:
输出结果
使用场景
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两个方面封装在独立
的对象中使它们可以各自独立地改变和复用。 - 一个对象的改变将导致一个或多个其他对象也发生改变,而并不知道具体有多少对象将
发生改变,也不知道这些对象是谁。 - 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,
可以使用观察者模式创建一种链式触发机制。
优缺点
优点:
- 实现了观察者和目标之间的抽象耦合
- 实现了动态联动(一个操作会引起其它相关的操作)
- 支持广播通信
缺点
- 互为观察者与被观察者间有循环依赖的话,要注意相互通知引起的死循环!
- 可能会引起武威操作,误更新。