观察者模式
一、什么是观察者模式?
观察者模式(Observer Design Pattern):多个对象之间存在一对多的关系,当一个对象的状态发生改变时,所有其他依赖的对象都会收到通知。
观察者模式也被称为发布-订阅模式。
负责通知其他依赖对象称为被观察者,被通知的对象称为观察者。
在现实中,对象之间总是存在依赖关系的,一个对象的状态改变,往往会影响到其他的依赖对象。
观察者模式主要用于一对多的关系的情况,当某个对象状态发生改变时,需要通知其他所有的依赖对象。
比如说公众号订阅、天气预报通知等,都属于观察者模式。
二、为什么要用观察者模式?
为什么要用观察者模式?
假如不用观察者模式,那按照正常的逻辑,一对多的影响关系应该如何做呢?
没办法,只能把所有依赖对象都放在状态对象里面,当状态改变后,逐个调用依赖对象的接口去通知变更。
- 状态对象必须知道各个依赖对象的存在以及它们的类型,才能准确地调用它们的接口
- 一旦要新增依赖对象,只能去修改状态对象的代码
- 没办法很好做到动态添加和删除依赖对象,灵活性不够
- 状态对象和依赖对象都放在一起,代码耦合性高,而且扩展性很差
观察者模式,目的就是为了将依赖对象解耦,并且实现动态添加和删除依赖对象。
三、观察者模式怎么用?
观察者模式中的几个角色:
- 抽象被观察者(Subject):表示被观察的对象,定义了注册、删除、通知观察者的方法。
- 具体被观察者(ConcreteSubject):具体被观察对象的实现,主要是状态变化后,通知所有观察者的实现
- 抽象观察者(Observer):抽象观察者,定义了被通知的接口回调方法
- 具体观察者(ConcreteObserver):实现了抽象观察者的通知方法,执行具体的行为
观察者模式结构:

示例程序结构:

示例程序代码:
观察者:
1 2 3 4
| public interface Observer { void update(NumberGenerator generator); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class DigitObserver implements Observer {
@Override public void update(NumberGenerator generator) { System.out.println("DigitObserver: " + generator.getNumber()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class GraphObserver implements Observer {
@Override public void update(NumberGenerator generator) { System.out.println("GraphObserver: "); int count = generator.getNumber(); for (int i = 0; i < count; i++) { System.out.print("*"); } System.out.println(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } }
}
|
被观察者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public abstract class NumberGenerator { private List<Observer> observers = new ArrayList<>(); public void addObserver(Observer observer) { observers.add(observer); }
public void removeObserver(Observer observer) { observers.remove(observer); }
public void notifyObservers() { for (Observer observer : observers) { observer.update(this); } } public abstract int getNumber(); public abstract void execute();
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class RandomNumberGenerator extends NumberGenerator {
private Random random = new Random(); private int number;
@Override public int getNumber() { return number; }
@Override public void execute() { for (int i = 0; i < 20; i++) { number = random.nextInt(50); notifyObservers(); } } }
|
四、观察者模式有什么优缺点?
优点:
- 降低了被观察者与观察者的耦合度
- 提高了灵活性,方便新增和删除观察者对象
缺点:
- 在多对多的情况下,观察者之间可能会比较混乱,容易出现循环