设计模式之观察者模式

概念

观察者模式(Observer)定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己

优点

  • 促进了松耦合,允许主题及其观察者在没有紧密依赖的情况下进行交互,从而简化了维护和可伸缩性
  • 允许动态订阅和取消订阅观察者

什么时候使用观察者模式

  • 当一个抽象有两个方面时,其中一个依赖于另一个。将这些方面封装在单独的对象中,可以独立地更改和重用它们
  • 当对一个对象的更改需要更改其他对象时,而且通常你不知道需要更改多少对象
  • 一个对象应该能够通知其他对象,而不需要假设这些对象是谁。换句话说,你不希望这些对象紧密耦合

示例

霍比特人和半兽人(观察者)对天气(主题)的反应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public interface WeatherObserver {

void update(WeatherType currentWeather);
}

public class Orcs implements WeatherObserver {

@Override
public void update(WeatherType currentWeather) {
LOGGER.info("The orcs are facing " + currentWeather.getDescription() + " weather now");
}
}

public class Hobbits implements WeatherObserver {

@Override
public void update(WeatherType currentWeather) {
switch (currentWeather) {
LOGGER.info("The hobbits are facing " + currentWeather.getDescription() + " weather now");
}
}
}
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
28
29
30
31
32
33
34
public class Weather {

private WeatherType currentWeather;
private final List<WeatherObserver> observers;

public Weather() {
observers = new ArrayList<>();
currentWeather = WeatherType.SUNNY;
}

public void addObserver(WeatherObserver obs) {
observers.add(obs);
}

public void removeObserver(WeatherObserver obs) {
observers.remove(obs);
}

/**
* Makes time pass for weather.
*/
public void timePasses() {
var enumValues = WeatherType.values();
currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length];
LOGGER.info("The weather changed to {}.", currentWeather);
notifyObservers();
}

private void notifyObservers() {
for (var obs : observers) {
obs.update(currentWeather);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void main(String[] args) {

var weather = new Weather();
weather.addObserver(new Orcs());
weather.addObserver(new Hobbits());

weather.timePasses();
weather.timePasses();
weather.timePasses();
weather.timePasses();

// Generic observer inspired by Java Generics and Collections by Naftalin & Wadler
LOGGER.info("--Running generic version--");
var genericWeather = new GenWeather();
genericWeather.addObserver(new GenOrcs());
genericWeather.addObserver(new GenHobbits());

genericWeather.timePasses();
genericWeather.timePasses();
genericWeather.timePasses();
genericWeather.timePasses();
}
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
21:28:08.310 [main] INFO com.iluwatar.observer.Weather -- The weather changed to rainy.
21:28:08.312 [main] INFO com.iluwatar.observer.Orcs -- The orcs are facing Rainy weather now
21:28:08.312 [main] INFO com.iluwatar.observer.Hobbits -- The hobbits are facing Rainy weather now
21:28:08.312 [main] INFO com.iluwatar.observer.Weather -- The weather changed to windy.
21:28:08.312 [main] INFO com.iluwatar.observer.Orcs -- The orcs are facing Windy weather now
21:28:08.312 [main] INFO com.iluwatar.observer.Hobbits -- The hobbits are facing Windy weather now
21:28:08.312 [main] INFO com.iluwatar.observer.Weather -- The weather changed to cold.
21:28:08.312 [main] INFO com.iluwatar.observer.Orcs -- The orcs are facing Cold weather now
21:28:08.312 [main] INFO com.iluwatar.observer.Hobbits -- The hobbits are facing Cold weather now
21:28:08.312 [main] INFO com.iluwatar.observer.Weather -- The weather changed to sunny.
21:28:08.312 [main] INFO com.iluwatar.observer.Orcs -- The orcs are facing Sunny weather now
21:28:08.312 [main] INFO com.iluwatar.observer.Hobbits -- The hobbits are facing Sunny weather now
21:28:08.312 [main] INFO com.iluwatar.observer.App -- --Running generic version--
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenWeather -- The weather changed to rainy.
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenOrcs -- The orcs are facing Rainy weather now
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenHobbits -- The hobbits are facing Rainy weather now
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenWeather -- The weather changed to windy.
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenOrcs -- The orcs are facing Windy weather now
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenHobbits -- The hobbits are facing Windy weather now
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenWeather -- The weather changed to cold.
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenOrcs -- The orcs are facing Cold weather now
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenHobbits -- The hobbits are facing Cold weather now
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenWeather -- The weather changed to sunny.
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenOrcs -- The orcs are facing Sunny weather now
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenHobbits -- The hobbits are facing Sunny weather now

注意事项

  • 如果没有正确注销观察者,可能导致内存泄漏
  • 未指定通知的顺序,可能导致潜在的意外行为
  • 大量观察者可能导致性能问题

设计模式之观察者模式
http://s1mplecode.com/design-pattern/observer.html
作者
Jago
发布于
2024年12月24日
许可协议