JAVA设计模式——Observer观察者

本文的设计模式来源于github上人气比较高的iluwatar/java-design-patterns,包含了23种经典设计模式和很多实际应用中涉及到的模式。

文中涉及到的示例代码可能只抽取了部分进行讲解,如果有本地模拟需求,请参考源码。

“设计模式是程序员在设计应用程序时能够解决场景问题的最佳实现,通过经测试和验证的开发范例,可以提高开发效率。重用设计模式,可有效避免可能因细微问题而导致的重大隐患,同时有助于提升熟悉设计模式的编码人员和架构师对代码的可读性。”

作用

观察者模式Obesrver,也可称作DependentsPublish-Subscribe)。在对象与对象之间定义一种一对多的依赖关系,当一个对象的状态变化后,其他依赖该对象的对象组将会自动收到通知以及做相应更新。

适用性

  1. 当一个抽象事物存在两种属性,其中一种依赖于另外一种时,可以将这两种有依赖关系的属性封装在互相隔离的对象中,并可以单独地去修改和使用;
  2. 当更改一个对象同时需要更改其他对象,而又不确认需要更改多少个其他对象时;
  3. 当一个对象需要通知其他对象,而又不需要或者不想关心要通知的对象是谁时,可以使用观察者模式。

典型用例

  1. 一个对象的变化导致其他对象的变化。

代码示例

以天气对兽人和霍比特人的影响为例。兽人和霍比特人同时感知到天气的变化,表现出不同的行为。

观察者(订阅者)

定义观察者,这里有两个观察者——霍比特人和兽人。

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// 观察者定义
public interface WeatherObserver {
void update(WeatherType currentWeather);
}
// 观察者——霍比特人
public class Hobbits implements WeatherObserver {
private static final Logger LOGGER = LoggerFactory.getLogger(Hobbits.class);
@Override
public void update(WeatherType currentWeather) {
switch (currentWeather) {
case COLD:
LOGGER.info("The hobbits are shivering in the cold weather.");
break;
case RAINY:
LOGGER.info("The hobbits look for cover from the rain.");
break;
case SUNNY:
LOGGER.info("The happy hobbits bade in the warm sun.");
break;
case WINDY:
LOGGER.info("The hobbits hold their hats tightly in the windy weather.");
break;
default:
break;
}
}
}
// 观察者——兽人
public class Orcs implements WeatherObserver {
private static final Logger LOGGER = LoggerFactory.getLogger(Orcs.class);
@Override
public void update(WeatherType currentWeather) {
switch (currentWeather) {
case COLD:
LOGGER.info("The orcs are freezing cold.");
break;
case RAINY:
LOGGER.info("The orcs are dripping wet.");
break;
case SUNNY:
LOGGER.info("The sun hurts the orcs' eyes.");
break;
case WINDY:
LOGGER.info("The orc smell almost vanishes in the wind.");
break;
default:
break;
}
}
}

被观察者(发布者)

定义被观察者——天气

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
public class Weather {
private static final Logger LOGGER = LoggerFactory.getLogger(Weather.class);
// 当前天气
private WeatherType currentWeather;
// 观察者(订阅者)列表
private 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);
}
// 天气随着时间的变化而变化
public void timePasses() {
WeatherType[] enumValues = WeatherType.values();
currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length];
LOGGER.info("The weather changed to {}.", currentWeather);
// 天气变化,通知观察者
notifyObservers();
}
// 通知
private void notifyObservers() {
for (WeatherObserver obs : observers) {
obs.update(currentWeather);
}
}
}
1
2
3
4
5
6
7
public static void main(String[] args) {
Weather weather = new Weather();
weather.addObserver(new Orcs());
weather.addObserver(new Hobbits());
weather.timePasses();
weather.timePasses();
}

类图

URL类图