概述:
观察者模式
有时又被称为发布(publish
)-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式。
举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。
实现方式:
观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动执行相应动作。
那么这里就有两个角色,被观察者(Observable)和观察者(Observer)。
被观察者:包含一个观察者的容器,注册和注销观察者的方法,还有通知观察者的方法。
观察者:包含一个收到通知后执行的方法。
以上只是一个最基本的观察者模式的代码设计框架,往往实际运用时需要扩展。另外,在实际运用中,常常结合监听器等来实现观察者模式,如Spring的各种Listener。
下面我们来看一种最基本的观察者模式的代码实现:
被观察者抽象类(Observable):
public abstract class Observable {
private final ArrayList<Observer> observers = new ArrayList<Observer>();
private final Object lock = new Object();
/**
* 注册观察者
* @param observer 观察者实例
*/
public void registerObserver(Observer observer) {
if(observer == null) throw new NullPointerException("Null Observer" );
// 这里的同步是防止多线程同时对同一个观察者实例进行注册
synchronized (lock ) {
if(!observers .contains(observer))
observers.add(observer );
}
}
/**
* 注销观察者
* @param observer
*/
public void unRegisterObserver(Observer observer){
observers.remove(observer );
}
/**
* 通知观察者
*/
public void notifyObservers() {
for(Observer obj : observers ) {
obj.update();
}
}
}
观察者接口(Observer):
public interface Observer {
public void update();
}
被观察者具体类(ConcreteObservable)
:
public class ConcreteObservable extends Observable {
// 这里没有重写父类的方法,有需要可重写
}
观察者具体类(ConcreteObserver):
public class ConcreteObserver implements Observer {
private String name ;
public ConcreteObserver(String name ) {
this.name = name ;
}
@Override
public void update() {
System. out.println(name + " update!!!" );
}
}
测试代码
:
public static void main(String[] args) {
ConcreteObservable subject = new ConcreteObservable();
ConcreteObserver observer1 = new ConcreteObserver("observer1");
ConcreteObserver observer2 = new ConcreteObserver("observer2");
ConcreteObserver observer3 = new ConcreteObserver("observer3");
subject.registerObserver( observer1);
subject.registerObserver( observer2);
subject.registerObserver( observer3);
subject.notifyObservers();
}
使用场景:
一般符合以下场景条件的场景即可使用观察者模式:
- 对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变。
- 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。
注意事项:
在应用观察者模式编写代码的时候,应该基于接口编程,而不是具体类,这样可以为程序提供更大的灵活性。意思就是被观察者和观察者之间不需要知道彼此的具体类型,如本文例子,只需要确认被观察是继承自Obervable,观察者是实现了Oberver接口即可。