理解
生活中有个例子,拍卖师拍卖物品时,会根据最高叫价标价,然后通知其他竞价者。这个例子中竞价者是观察者,拍卖师是被观察者。
观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新
使用场景
-
对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态改变。
-
对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。
结构
Subject: 抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
ConcreteSubject: 具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
Observer: 抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
ConcrereObserver: 具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。
实例
Subject
public interface Subject<T> {
List<Observer> list = new ArrayList<>();
void addObserver(T obs);
void deleteObserver(T obs);
void notifyAllObservers();
}
ConcreteSubject
@Data
public class ConcreteSubject implements Subject<Observer> {
private int state;
public void set(int state) {
this.state = state;
this.notifyAllObservers();
}
@Override
public void addObserver(Observer obs) {
list.add(obs);
}
@Override
public void deleteObserver(Observer obs) {
list.remove(obs);
}
@Override
public void notifyAllObservers() {
for (Observer obs : list) {
obs.update(this);
}
}
}
Observer
public interface Observer {
void update(Subject subject);
}
ConcrereObserver
@Data
public class ObserverA implements Observer {
private int state;
@Override
public void update(Subject subject) {
this.state = ((ConcreteSubject) subject).getState();
}
}
@Data
public class ObserverB implements Observer {
private int state;
@Override
public void update(Subject subject) {
this.state = ((ConcreteSubject) subject).getState();
}
}
Client
public class Test {
public static void main(String[] args) {
ConcreteSubject concreteSubject = new ConcreteSubject();
ObserverA observerA = new ObserverA();
ObserverB observerB = new ObserverB();
concreteSubject.addObserver(observerA);
concreteSubject.addObserver(observerB);
System.out.println("observerA " + observerA.getState());
System.out.println("observerB " + observerB.getState());
System.out.println("=============");
concreteSubject.set(1);
System.out.println("observerA " + observerA.getState());
System.out.println("observerB " + observerB.getState());
System.out.println("=============");
concreteSubject.deleteObserver(observerB);
concreteSubject.set(2);
System.out.println("observerA " + observerA.getState());
System.out.println("observerB " + observerB.getState());
}
}
运行结果…
observerA 0
observerB 0
=============
observerA 1
observerB 1
=============
observerA 1
observerB 2
Java中提供了 java.util.Observable
和 java.util.Observable
来实现观察者模式
@Data
public class ConcreteSubject extends Observable {
private int state;
public void set(int s) {
state = s;
setChanged();
notifyObservers(state);
}
}
@Data
public class ObserverA implements Observer {
private int state;
@Override
public void update(Observable o, Object arg) {
this.state = ((ConcreteSubject) o).getState();
}
}
@Data
public class ObserverB implements Observer {
private int state;
@Override
public void update(Observable o, Object arg) {
this.state = ((ConcreteSubject) o).getState();
}
}
public class Test {
public static void main(String[] args) {
ConcreteSubject concreteSubject = new ConcreteSubject();
ObserverA observerA = new ObserverA();
ObserverB observerB = new ObserverB();
concreteSubject.addObserver(observerA);
concreteSubject.addObserver(observerB);
System.out.println("observerA " + observerA.getState());
System.out.println("observerB " + observerB.getState());
System.out.println("=============");
concreteSubject.set(1);
System.out.println("observerA " + observerA.getState());
System.out.println("observerB " + observerB.getState());
System.out.println("=============");
concreteSubject.deleteObserver(observerA);
concreteSubject.set(2);
System.out.println("observerA " + observerA.getState());
System.out.println("observerB " + observerB.getState());
}
}
观察者模式的优缺点
优点
- 解耦,被观察者只知道观察者列表「抽象接口」,被观察者不知道具体的观察者
- 被观察者发送通知,所有注册的观察者都会收到信息「可以实现广播机制」
缺点
- 如果观察者非常多的话,那么所有的观察者收到被观察者发送的通知会耗时
- 观察者知道被观察者发送通知了,但是观察者不知道所观察的对象具体是如何发生变化的
- 如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调用,会导致系统崩溃