观察者模式

观察者模式

一、什么是观察者模式?

观察者模式(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();
}
}
}

四、观察者模式有什么优缺点?

优点:

  • 降低了被观察者与观察者的耦合度
  • 提高了灵活性,方便新增和删除观察者对象

缺点:

  • 在多对多的情况下,观察者之间可能会比较混乱,容易出现循环
作者

jiaduo

发布于

2022-01-15

更新于

2023-04-03

许可协议