观察者模式详解

什么是观察者模式?

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系,使得当一个对象状态发生变化时,所有依赖它的对象都会自动收到通知并更新。

核心概念

  • Subject(主题/被观察者):维护一组观察者对象,提供添加和删除观察者的方法,当状态变化时通知所有观察者。
  • Observer(观察者):定义接收通知的接口,当主题状态变化时更新自己。
  • ConcreteSubject(具体主题):实现主题接口,维护状态,当状态变化时通知观察者。
  • ConcreteObserver(具体观察者):实现观察者接口,存储与主题相关的状态,当收到通知时更新自己。

观察者模式的UML图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
+----------------+       +----------------+
| Subject |<------| Observer |
+----------------+ +----------------+
| +attach() | | +update() |
| +detach() | +----------------+
| +notify() | ^
+----------------+ |
^ |
| |
+----------------+ +----------------+
| ConcreteSubject| | ConcreteObserver|
+----------------+ +----------------+
| -state | | -observerState |
| +getState() | | +update() |
| +setState() | +----------------+
+----------------+

观察者模式的优缺点

优点

  1. 松耦合:主题和观察者之间是松耦合的,它们可以独立变化。
  2. 可扩展性:可以轻松添加新的观察者,而不需要修改主题的代码。
  3. 广播通信:主题可以同时通知多个观察者,实现一对多的通信。
  4. 符合开闭原则:对扩展开放,对修改关闭。

缺点

  1. 内存泄漏:如果观察者没有正确从主题中移除,可能会导致内存泄漏。
  2. 通知顺序:观察者的通知顺序是不确定的,可能会导致依赖于顺序的问题。
  3. 性能问题:如果观察者数量过多,可能会影响通知的性能。

观察者模式的实现

C++ 实现

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
#include <iostream>
#include <vector>
#include <string>

// 观察者接口
class Observer {
public:
virtual ~Observer() = default;
virtual void update(const std::string& message) = 0;
};

// 主题接口
class Subject {
public:
virtual ~Subject() = default;
virtual void attach(Observer* observer) = 0;
virtual void detach(Observer* observer) = 0;
virtual void notify() = 0;
};

// 具体主题
class ConcreteSubject : public Subject {
private:
std::vector<Observer*> observers;
std::string message;

public:
void attach(Observer* observer) override {
observers.push_back(observer);
}

void detach(Observer* observer) override {
auto it = std::find(observers.begin(), observers.end(), observer);
if (it != observers.end()) {
observers.erase(it);
}
}

void notify() override {
for (Observer* observer : observers) {
observer->update(message);
}
}

void setMessage(const std::string& msg) {
this->message = msg;
notify();
}

std::string getMessage() const {
return message;
}
};

// 具体观察者
class ConcreteObserver : public Observer {
private:
std::string name;
ConcreteSubject& subject;
std::string observerState;

public:
ConcreteObserver(std::string name, ConcreteSubject& subject)
: name(std::move(name)), subject(subject) {}

void update(const std::string& message) override {
observerState = message;
std::cout << "Observer " << name << " received message: " << message << std::endl;
}
};

// 测试代码
int main() {
// 创建主题
ConcreteSubject subject;

// 创建观察者
ConcreteObserver observer1("Observer 1", subject);
ConcreteObserver observer2("Observer 2", subject);
ConcreteObserver observer3("Observer 3", subject);

// 注册观察者
subject.attach(&observer1);
subject.attach(&observer2);
subject.attach(&observer3);

// 更改主题状态
std::cout << "Setting message to 'Hello World'" << std::endl;
subject.setMessage("Hello World");

// 移除一个观察者
std::cout << "\nRemoving Observer 2" << std::endl;
subject.detach(&observer2);

// 再次更改主题状态
std::cout << "Setting message to 'Observer Pattern'" << std::endl;
subject.setMessage("Observer Pattern");

return 0;
}

Java 实现

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
import java.util.ArrayList;
import java.util.List;

// 观察者接口
interface Observer {
void update(String message);
}

// 主题接口
interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers();
}

// 具体主题
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private String message;

@Override
public void attach(Observer observer) {
observers.add(observer);
}

@Override
public void detach(Observer observer) {
observers.remove(observer);
}

@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(message);
}
}

public void setMessage(String msg) {
this.message = msg;
notifyObservers();
}

public String getMessage() {
return message;
}
}

// 具体观察者
class ConcreteObserver implements Observer {
private String name;
private ConcreteSubject subject;
private String observerState;

public ConcreteObserver(String name, ConcreteSubject subject) {
this.name = name;
this.subject = subject;
}

@Override
public void update(String message) {
this.observerState = message;
System.out.println("Observer " + name + " received message: " + message);
}
}

// 测试代码
public class ObserverPatternDemo {
public static void main(String[] args) {
// 创建主题
ConcreteSubject subject = new ConcreteSubject();

// 创建观察者
ConcreteObserver observer1 = new ConcreteObserver("Observer 1", subject);
ConcreteObserver observer2 = new ConcreteObserver("Observer 2", subject);
ConcreteObserver observer3 = new ConcreteObserver("Observer 3", subject);

// 注册观察者
subject.attach(observer1);
subject.attach(observer2);
subject.attach(observer3);

// 更改主题状态
System.out.println("Setting message to 'Hello World'");
subject.setMessage("Hello World");

// 移除一个观察者
System.out.println("\nRemoving Observer 2");
subject.detach(observer2);

// 再次更改主题状态
System.out.println("Setting message to 'Observer Pattern'");
subject.setMessage("Observer Pattern");
}
}

Python 实现

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
# 观察者模式的Python实现
class Observer:
"""观察者接口"""
def update(self, message):
"""接收通知并更新"""
pass

class Subject:
"""主题接口"""
def attach(self, observer):
"""添加观察者"""
pass

def detach(self, observer):
"""移除观察者"""
pass

def notify(self):
"""通知所有观察者"""
pass

class ConcreteSubject(Subject):
"""具体主题"""
def __init__(self):
self.observers = []
self.message = ""

def attach(self, observer):
if observer not in self.observers:
self.observers.append(observer)

def detach(self, observer):
if observer in self.observers:
self.observers.remove(observer)

def notify(self):
for observer in self.observers:
observer.update(self.message)

def set_message(self, message):
"""设置消息并通知观察者"""
self.message = message
self.notify()

def get_message(self):
return self.message

class ConcreteObserver(Observer):
"""具体观察者"""
def __init__(self, name, subject):
self.name = name
self.subject = subject
self.observer_state = ""

def update(self, message):
"""接收通知并更新状态"""
self.observer_state = message
print(f"Observer {self.name} received message: {message}")

# 测试代码
if __name__ == "__main__":
# 创建主题
subject = ConcreteSubject()

# 创建观察者
observer1 = ConcreteObserver("Observer 1", subject)
observer2 = ConcreteObserver("Observer 2", subject)
observer3 = ConcreteObserver("Observer 3", subject)

# 注册观察者
subject.attach(observer1)
subject.attach(observer2)
subject.attach(observer3)

# 更改主题状态
print("Setting message to 'Hello World'")
subject.set_message("Hello World")

# 移除一个观察者
print("\nRemoving Observer 2")
subject.detach(observer2)

# 再次更改主题状态
print("Setting message to 'Observer Pattern'")
subject.set_message("Observer Pattern")

C# 实现

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
using System;
using System.Collections.Generic;

// 观察者接口
interface IObserver
{
void Update(string message);
}

// 主题接口
interface ISubject
{
void Attach(IObserver observer);
void Detach(IObserver observer);
void Notify();
}

// 具体主题
class ConcreteSubject : ISubject
{
private List<IObserver> observers = new List<IObserver>();
private string message;

public void Attach(IObserver observer)
{
observers.Add(observer);
}

public void Detach(IObserver observer)
{
observers.Remove(observer);
}

public void Notify()
{
foreach (IObserver observer in observers)
{
observer.Update(message);
}
}

public void SetMessage(string msg)
{
this.message = msg;
Notify();
}

public string GetMessage()
{
return message;
}
}

// 具体观察者
class ConcreteObserver : IObserver
{
private string name;
private ConcreteSubject subject;
private string observerState;

public ConcreteObserver(string name, ConcreteSubject subject)
{
this.name = name;
this.subject = subject;
}

public void Update(string message)
{
this.observerState = message;
Console.WriteLine($"Observer {name} received message: {message}");
}
}

// 测试代码
class Program
{
static void Main(string[] args)
{
// 创建主题
ConcreteSubject subject = new ConcreteSubject();

// 创建观察者
ConcreteObserver observer1 = new ConcreteObserver("Observer 1", subject);
ConcreteObserver observer2 = new ConcreteObserver("Observer 2", subject);
ConcreteObserver observer3 = new ConcreteObserver("Observer 3", subject);

// 注册观察者
subject.Attach(observer1);
subject.Attach(observer2);
subject.Attach(observer3);

// 更改主题状态
Console.WriteLine("Setting message to 'Hello World'");
subject.SetMessage("Hello World");

// 移除一个观察者
Console.WriteLine("\nRemoving Observer 2");
subject.Detach(observer2);

// 再次更改主题状态
Console.WriteLine("Setting message to 'Observer Pattern'");
subject.SetMessage("Observer Pattern");
}
}

观察者模式的使用场景

1. 事件处理系统

  • GUI 应用:按钮点击、鼠标移动等事件的处理
  • 游戏开发:键盘输入、碰撞检测等事件的处理
  • 前端框架:React、Vue 等框架中的事件系统

2. 消息通知系统

  • 邮件订阅:用户订阅邮件列表,当有新邮件时通知用户
  • 新闻推送:用户订阅新闻频道,当有新闻时推送通知
  • 社交媒体:关注的人发布新内容时的通知

3. 状态监控系统

  • 监控系统:服务器状态、网络状态等的监控
  • 传感器网络:温度、湿度等传感器数据的监控
  • 金融系统:股票价格、汇率等的实时更新

4. 业务逻辑解耦

  • 微服务架构:服务之间的事件通知
  • 工作流系统:流程节点之间的状态传递
  • 插件系统:主程序与插件之间的通信

5. 其他场景

  • 配置管理:配置文件变化时的通知
  • 日志系统:日志级别变化时的通知
  • 缓存系统:缓存失效时的通知

适合使用观察者模式的问题

1. 当一个对象的状态变化需要通知多个其他对象时

例如:

  • 股票价格变化时,需要通知所有关注该股票的投资者
  • 天气变化时,需要通知所有订阅天气服务的用户

2. 当对象之间需要松耦合,以提高系统的可扩展性时

例如:

  • 电商系统中,订单状态变化时需要通知库存系统、支付系统、物流系统等
  • 游戏系统中,玩家状态变化时需要通知UI系统、成就系统、社交系统等

3. 当需要实现广播通信时

例如:

  • 聊天室中,一条消息需要广播给所有在线用户
  • 系统通知需要发送给所有相关模块

4. 当需要符合开闭原则,对扩展开放,对修改关闭时

例如:

  • 可以轻松添加新的观察者,而不需要修改主题的代码
  • 可以轻松添加新的主题,而不需要修改观察者的代码

5. 当需要避免组件之间的直接依赖时

例如:

  • 模块A不需要知道哪些模块依赖于它的状态变化
  • 模块B不需要知道它依赖的模块A的具体实现

观察者模式的变体

1. 推模型 vs 拉模型

  • 推模型:主题将详细信息推送给观察者
  • 拉模型:观察者根据需要从主题中拉取信息

2. 事件总线

事件总线是观察者模式的一种扩展,它提供了一个中央枢纽,用于管理事件的发布和订阅。

3. 消息队列

消息队列是一种更复杂的观察者模式实现,它提供了异步消息传递、消息持久化等功能。

4. 响应式编程

响应式编程是观察者模式的一种现代应用,它强调数据流和变化的传播。

实际应用案例

1. Java中的Observable和Observer

Java 内置了观察者模式的实现:java.util.Observablejava.util.Observer

2. C#中的事件和委托

C# 使用事件(Event)和委托(Delegate)来实现观察者模式。

3. JavaScript中的事件监听

JavaScript 使用事件监听机制来实现观察者模式,如 addEventListener

4. Python中的观察者模式实现

Python 可以使用内置的 observable 模块或第三方库来实现观察者模式。

5. 前端框架中的观察者模式

  • React:使用状态管理和生命周期方法实现观察者模式
  • Vue:使用响应式数据和 watch 实现观察者模式
  • Angular:使用 Observable 和 Subject 实现观察者模式

代码优化建议

1. 避免内存泄漏

  • 确保在观察者不再需要时,从主题中正确移除
  • 在 C++ 中,使用智能指针管理观察者的生命周期
  • 在 Java 中,考虑使用弱引用避免内存泄漏

2. 优化通知性能

  • 对于大量观察者的场景,考虑使用异步通知
  • 对于频繁更新的场景,考虑使用批处理或节流
  • 对于复杂的更新逻辑,考虑使用策略模式或模板方法模式

3. 增强灵活性

  • 考虑使用事件对象传递更丰富的信息
  • 考虑使用泛型或模板来增加代码的复用性
  • 考虑使用配置文件或注解来管理观察者的注册

4. 提高可测试性

  • 使用依赖注入来管理观察者和主题的依赖关系
  • 使用模拟对象(Mock)来测试观察者模式的行为
  • 使用单元测试来验证观察者模式的正确性

总结

观察者模式是一种非常实用的设计模式,它通过定义对象之间的一对多依赖关系,实现了对象之间的松耦合通信。无论是在GUI应用、消息系统还是状态监控系统中,观察者模式都有着广泛的应用。

通过本文的介绍,相信你已经对观察者模式有了更深入的了解。在实际开发中,当你遇到需要实现对象之间的一对多通信、需要松耦合设计或需要符合开闭原则的场景时,不妨考虑使用观察者模式。

记住,设计模式的选择应该基于具体的问题场景,而不是为了使用模式而使用模式。只有在合适的场景中使用合适的设计模式,才能真正发挥其价值。