行为式:观察者模式

1 基本介绍

​ 观察者模式是使用频率最高的设计模式之一。

​ 基本是:定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新

​ 别名又称为发布-订阅模式模型-视图模式源-监听者模式

image-20220317135413512

2 设计分析

​ 使用观察者模式来进行多人联机对战游戏的设计

2.1 栗子

image-20220317135633752

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package DesignPatterns.JavaDesign.Observer;

import java.util.ArrayList;

public class Test {
public static void main(String[] args) {
// 定义观察目标对象
AllyControlCenter acc;
acc = new ConcreteAllyControlCenter("金庸群侠");
// 定义四个观察者对象
Observer player1, player2, player3, player4;
player1 = new Player("杨过");
acc.join(player1);

player2 = new Player("令狐冲");
acc.join(player2);

player3 = new Player("张无忌");
acc.join(player3);

player4 = new Player("段誉");
acc.join(player4);

player1.beAttacked(acc);
}
}

interface Observer {
public String getName();
public void setName(String name);
public void help(); // 声明支援盟友方法
public void beAttacked(AllyControlCenter acc); // 声明遭受攻击方法
}

// 战队成员类:具体观察者类
class Player implements Observer {

private String name;

public Player(String name) {
this.name = name;
}

@Override
public String getName() {
return name;
}

@Override
public void setName(String name) {
this.name = name;
}

// 支援盟友方法的实现
@Override
public void help() {
System.out.println("坚持住," + this.name + "来救你");
}

// 遭受攻击方法的实现,当遭受攻击时将调用战队控制中心类的通知方法notifyObserver
@Override
public void beAttacked(AllyControlCenter acc) {
System.out.println(this.name + "被攻击");
acc.notifyObserver(name);
}
}

abstract class AllyControlCenter {
protected String allyName; // 战队名称
protected ArrayList<Observer> players = new ArrayList<Observer>();

public String getAllyName() {
return allyName;
}

public void setAllyName(String allyName) {
this.allyName = allyName;
}

public void join(Observer obs) {
System.out.println(obs.getName() + "加入" + this.allyName);
players.add(obs);
}

// 注销方法
public void quit(Observer obs) {
System.out.println(obs.getName() + "退出" + this.allyName);
players.remove(obs);
}

// 声明抽象通知方法
public abstract void notifyObserver(String name);
}

// 具体战队控制中心类:具体目标类
class ConcreteAllyControlCenter extends AllyControlCenter {

public ConcreteAllyControlCenter(String allyName) {
System.out.println(allyName + "战队组建成功!");
System.out.println("--------------------");
this.allyName = allyName;
}

@Override
public void notifyObserver(String name) {
System.out.println(this.allyName + "战队紧急通知,盟友" + name);
// 遍历观察者集合,调用每一个盟友的支援方法
for (Observer player : players) {
if (!((Observer)player).getName().equalsIgnoreCase(name)) {
((Observer)player).help();
}
}
}
}

​ 在本例中,实现了两次对象之间的联动,当一个游戏玩家Player对象的beAttacked()方法被调用时,将调用AllyControlCenternotifyObserver()方法来进行处理,而在notifyObserver()方法中又将调用其他Player对象的help()方法。

Player.beAttacked() –> AllyControlCenter.notifyObserver() –>Player

3 总结

优缺点分析

优点:

  1. 实现表示层和数据逻辑层的分离,定义了稳定的消息更新传递机制
  2. 观察者模式在观察目标和观察者之间建立一个抽象的耦合。
  3. 观察者模式支持广播通信,观察目标会向所有已注册的观察者对象发送通知,简化了一对多系统设计的难度。
  4. 观察者模式满足“开闭原则”的要求,增加新的具体观察者无须修改原有系统代码

缺点:

  1. 如果一个观察目标对象有很多直接和间接观察者,将所有的观察者都通知到会花费很多时间
  2. 如果在观察者和观察目标之间存在循环依赖,观察目标会触发它们之间进行循环调用,可能导致系统崩溃
  3. 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

4 场景使用

4.1 Spring中ApplicationContext的使用

ApplicationContext事件机制是观察者设计模式的实现,通过 ApplicationEvent类和 ApplicationListener 接口,可以实现 ApplicationContext事件处理。 如果容器中有一个 ApplicationListener Bean ,每当 ApplicationContext 发布 ApplicationEvent 时,ApplicationListener Bean 将自动被触发。这种事件机制都必须需要程序显示的触发。

​ ApplicationContext事件监听

​ 当ApplicationContext内的Bean对象初始化完成时,此时可以通过监听 ContextRefreshedEvent 得到通知

image-20220317144156644

​ 将对象添加到容器中

image-20220317144210447

image-20220317144215098

image-20220317144221216

参考

(111条消息) 设计模式之Spring中观察者模式_字节跳动的博客-CSDN博客_spring中的观察者模式


行为式:观察者模式
https://2w1nd.github.io/2022/03/15/设计模式/行为式:观察者模式/
作者
w1nd
发布于
2022年3月15日
许可协议