跳到主要内容

设计模式之观察者模式

观察者模式定义

观察者模式(Observer Pattern)又称发布-订阅模式(Publish/Subscribe Pattern),即多个观察者同时观察某个对象,一旦被观察者发生变化,所有观察者便及时做出响应。但需要注意的是,观察者并不会主动去观察对象,而是被动的接受通知。正如你订阅某个杂志,并不会主动到杂志社询问杂志是否投递,而是等待投递员通知你。同样的,一种杂志并不只有一个订阅者,一个订阅者也不一定只订阅一个杂志。如果程序中有不定数对象需要根据某个对象的状态发生变化时,便可以使用观察者模式。

观察者模式的实现

实现观察者模式需要注意以下几点:

  1. 避免循环观察,以免陷入无穷的相互通知中。
  2. 正确处理观察者可能出现的问题(异常、耗时操作导致阻塞等)
  3. 由被观察者通知观察者
// 主题/抽象通知者
public abstract class Subject {
// 记录观察者
private List<Observer> observers = new ArrayList<>();

// 添加观察者
public void attach(Observer observer) {
observers.add(observer);
}

// 移除观察者
public void detach(Observer observer) {
observers.remove(observer);
}

// 通知观察者状态变化
public void notifyAllObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}

// 抽象观察者
public abstract class Observer {
// 更新方法,观察者响应变化
public abstract void update();
}

测试:

// 某个被观察者
public class OneSubject extends Subject {
// 某个状态
private Object state;

public Object getState() {
return state;
}

public void setState(Object state) {
this.state = state;
}
}

// 某个观察者
public class OneObserver extends Observer {
private OneSubject subject;

public OneObserver(OneSubject subject) {
this.subject = subject;
}

@Override
public void update() {
System.out.println("得到了一个状态:" + subject.getState());
}
}

public class Main {
public static void main(String[] args) {
OneSubject subject = new OneSubject();
subject.attach(new OneObserver(subject));
subject.attach(new OneObserver(subject));
subject.setState("新的状态");
subject.notifyAllObservers();
}
}

结果:

得到了一个状态:新的状态
得到了一个状态:新的状态

被观察者发生变化时,有可能只是通知观察者,也可能会互相传递数据,因此不宜在抽象通知者中编写传递数据之类的方法。此外,抽到观察者也可改成写接口,以方便在单继承语言中减少代码书写。

接口方式的抽象观察者:

// 接口形式的抽象观察者
public interface Observer {
void update();
}

// 单继承时同时实现抽象观察者
public class OneObserver extends Object implements Observer {
private OneSubject subject;

public OneObserver(OneSubject subject) {
this.subject = subject;
}

@Override
public void update() {
System.out.println("得到了一个状态:" + subject.getState());
}
}