观察者模式

观察者模式(Observer Pattern)是一种经典的行为型设计模式,其核心思想是定义对象间的一对多依赖关系,当一个对象(被观察者)的状态发生变化时,所有依赖于它的对象(观察者)都会被自动通知并更新,实现“状态变更-自动通知-同步更新”的闭环逻辑。这种模式将被观察者与观察者解耦,让两者专注于自身核心职责,大幅提升代码的灵活性、可扩展性与可维护性,是处理对象间联动场景的核心设计范式。

观察者模式的核心价值在于“解耦联动逻辑,简化状态同步”,它避免了被观察者与观察者之间的直接耦合,通过抽象接口建立通信桥梁,使得新增观察者或修改观察者逻辑时,无需改动被观察者代码,完美契合“单一职责原则”与“开闭原则”。在实际开发中,诸如消息通知、状态同步、事件监听等场景,均能通过观察者模式高效实现。

一、观察者模式的核心结构

观察者模式的结构清晰,角色分工明确,核心由四个角色构成,各角色协同工作,共同实现“状态变更通知与同步更新”的核心目标,确保联动逻辑的解耦与可扩展:

1.1 被观察者(Subject)

也称为主题(Subject),是状态变化的核心载体,负责维护一组观察者的引用,提供注册(添加观察者)、注销(移除观察者)和通知(状态变更时触发所有观察者更新)的核心方法。被观察者无需知晓具体观察者的实现细节,仅需通过抽象观察者接口与观察者交互。

1.2 抽象观察者(Observer)

定义观察者的统一接口,声明一个更新方法(如Update()),是所有具体观察者的行为契约。当被观察者状态发生变化时,会调用该接口的更新方法,触发观察者执行相应的业务逻辑。

1.3 具体观察者(Concrete Observer)

实现抽象观察者接口,是接收被观察者通知并执行具体更新逻辑的类。它持有被观察者的引用(可选),当收到通知时,根据被观察者的状态变化执行相应的业务操作,完成自身状态的同步或业务逻辑的触发。

1.4 客户端(Client)

负责创建被观察者和具体观察者实例,完成观察者的注册/注销操作,触发被观察者的状态变更。客户端无需关心被观察者与观察者之间的通信细节,仅需通过公开接口完成对象初始化与交互。

核心逻辑链路:客户端 → 实例化被观察者与具体观察者 → 注册观察者到被观察者 → 被观察者状态变更 → 被观察者遍历所有注册的观察者 → 调用观察者的更新方法 → 所有观察者同步更新。整个过程中,被观察者与观察者通过抽象接口通信,完全解耦。

二、多语言实现观察者模式

为便于开发者落地实践,本文以“天气预警系统”为经典案例,实现多语言版本的观察者模式:被观察者为“天气中心”,负责推送天气状态变更;具体观察者为“手机APP”“气象看板”“短信通知”,接收天气变更通知并执行对应逻辑。所有实现均保证完整可运行,贴合各语言设计理念,补充规范注释、异常处理和边界判断,兼顾实用性与可读性,同时体现各语言对观察者模式的适配方式。

2.1 C# 实现(依托接口,贴合面向对象规范)

C# 作为强类型面向对象语言,通过接口严格定义被观察者与观察者的契约,利用泛型提升代码通用性,依托GC自动管理内存,代码结构严谨、可读性高,适配企业级业务系统开发,是观察者模式最常用的实现方式之一。

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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
using System;
using System.Collections.Generic;

/// <summary>
/// 抽象观察者接口:定义观察者的更新契约
/// </summary>
public interface IObserver
{
/// <summary>
/// 接收被观察者通知,执行更新逻辑
/// </summary>
/// <param name="weatherInfo">被观察者传递的状态信息(天气信息)</param>
void Update(string weatherInfo);
}

/// <summary>
/// 被观察者(主题):天气中心
/// 负责维护观察者列表,触发状态变更通知
/// </summary>
public class WeatherSubject
{
// 存储注册的观察者列表(线程安全考虑,使用锁机制)
private readonly List<IObserver> _observers = new List<IObserver>();
// 被观察者的核心状态:当前天气信息
private string _currentWeather;

/// <summary>
/// 注册观察者(添加到观察者列表)
/// </summary>
/// <param name="observer">具体观察者实例</param>
public void RegisterObserver(IObserver observer)
{
if (observer == null)
throw new ArgumentNullException(nameof(observer), "观察者实例不可为null");

lock (_observers)
{
if (!_observers.Contains(observer))
_observers.Add(observer);
}
}

/// <summary>
/// 注销观察者(从观察者列表中移除)
/// </summary>
/// <param name="observer">具体观察者实例</param>
public void RemoveObserver(IObserver observer)
{
if (observer == null)
throw new ArgumentNullException(nameof(observer), "观察者实例不可为null");

lock (_observers)
{
_observers.Remove(observer);
}
}

/// <summary>
/// 通知所有注册的观察者(状态变更时触发)
/// </summary>
private void NotifyObservers()
{
lock (_observers)
{
// 遍历所有观察者,调用更新方法
foreach (var observer in _observers)
{
observer.Update(_currentWeather);
}
}
}

/// <summary>
/// 更新天气状态(模拟天气变化)
/// </summary>
/// <param name="weatherInfo">新的天气信息</param>
public void SetWeather(string weatherInfo)
{
if (string.IsNullOrEmpty(weatherInfo))
throw new ArgumentException("天气信息不可为空或空白", nameof(weatherInfo));

// 更新自身状态
_currentWeather = weatherInfo;
// 状态变更后,通知所有观察者
NotifyObservers();
}
}

/// <summary>
/// 具体观察者1:手机APP
/// 接收天气通知,显示天气信息
/// </summary>
public class PhoneAppObserver : IObserver
{
public void Update(string weatherInfo)
{
Console.WriteLine($"C# 手机APP:收到天气更新 - {weatherInfo},已同步显示");
}
}

/// <summary>
/// 具体观察者2:气象看板
/// 接收天气通知,更新看板展示
/// </summary>
public class WeatherBoardObserver : IObserver
{
public void Update(string weatherInfo)
{
Console.WriteLine($"C# 气象看板:收到天气更新 - {weatherInfo},已刷新看板");
}
}

// 客户端测试代码
class Program
{
static void Main()
{
try
{
// 1. 初始化被观察者(天气中心)
var weatherSubject = new WeatherSubject();

// 2. 初始化具体观察者
IObserver phoneApp = new PhoneAppObserver();
IObserver weatherBoard = new WeatherBoardObserver();

// 3. 注册观察者到被观察者
weatherSubject.RegisterObserver(phoneApp);
weatherSubject.RegisterObserver(weatherBoard);

// 4. 模拟天气状态变更,触发通知
Console.WriteLine("C# 模拟天气状态变更:晴转多云");
weatherSubject.SetWeather("晴转多云,气温18-25℃");

// 5. 注销观察者(模拟用户卸载APP)
weatherSubject.RemoveObserver(phoneApp);
Console.WriteLine("\nC# 模拟手机APP注销观察者");

// 6. 再次模拟天气状态变更
Console.WriteLine("C# 模拟天气状态变更:多云转雨");
weatherSubject.SetWeather("多云转雨,气温16-22℃,注意携带雨具");
}
catch (Exception ex)
{
Console.WriteLine($"C# 执行异常:{ex.Message}");
}
}
}

2.2 Python 实现(动态语言特性,简洁灵活)

Python 遵循“鸭子类型”,无需显式定义抽象接口,通过类的方法约定观察者与被观察者的行为,语法简洁灵活,无需繁琐的类型声明,依托GC自动管理内存,适配快速开发、脚本开发及轻量级项目场景,完整保留观察者模式的核心逻辑与解耦特性。

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
# 抽象观察者:通过方法约定行为(无需显式定义接口)
class Observer:
def update(self, weather_info):
"""接收被观察者通知,执行更新逻辑
Args:
weather_info (str): 被观察者传递的天气信息
""" raise NotImplementedError("具体观察者必须重写update方法")

# 被观察者(主题):天气中心
class WeatherSubject:
def __init__(self):
# 存储注册的观察者列表
self._observers = []
# 当前天气状态
self._current_weather = None

def register_observer(self, observer):
"""注册观察者""" if observer is None:
raise ValueError("观察者实例不可为None")
if observer not in self._observers:
self._observers.append(observer)

def remove_observer(self, observer):
"""注销观察者""" if observer in self._observers:
self._observers.remove(observer)

def _notify_observers(self):
"""通知所有注册的观察者(私有方法,内部触发)""" for observer in self._observers:
# 调用观察者的update方法,传递天气信息
observer.update(self._current_weather)

def set_weather(self, weather_info):
"""更新天气状态,触发通知""" if not weather_info or weather_info.strip() == "":
raise ValueError("天气信息不可为空或空白")
self._current_weather = weather_info
print(f"\nPython 模拟天气状态变更:{weather_info.split(',')[0]}")
self._notify_observers()

# 具体观察者1:手机APP
class PhoneAppObserver(Observer):
def update(self, weather_info):
print(f"Python 手机APP:收到天气更新 - {weather_info},已同步显示")

# 具体观察者2:气象看板
class WeatherBoardObserver(Observer):
def update(self, weather_info):
print(f"Python 气象看板:收到天气更新 - {weather_info},已刷新看板")

# 客户端测试代码
if __name__ == "__main__":
try:
# 初始化被观察者和观察者
weather_subject = WeatherSubject()
phone_app = PhoneAppObserver()
weather_board = WeatherBoardObserver()

# 注册观察者
weather_subject.register_observer(phone_app)
weather_subject.register_observer(weather_board)

# 模拟天气变更
weather_subject.set_weather("晴转多云,气温18-25℃")

# 注销观察者
weather_subject.remove_observer(phone_app)
print("Python 模拟手机APP注销观察者")

# 再次模拟天气变更
weather_subject.set_weather("多云转雨,气温16-22℃,注意携带雨具")
except Exception as e:
print(f"Python 执行异常:{str(e)}")

2.3 Go 实现(接口至上,轻量化解耦)

Go 语言无类和继承概念,核心遵循“组合优于继承”的设计哲学,通过接口定义被观察者与观察者的统一契约,结构体实现具体逻辑,代码极简、高效,贴合Go语言“简洁、务实、高性能”的设计理念,适配高并发、高性能的后端开发场景。

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
116
117
118
119
package main

import (
"fmt"
"sync"
)

// 抽象观察者接口:定义更新方法契约
type Observer interface {
Update(weatherInfo string) // 接收天气信息,执行更新
}

// 被观察者(主题):天气中心
type WeatherSubject struct {
observers []Observer // 观察者列表
mu sync.RWMutex // 读写锁,保证并发安全
weather string // 当前天气状态
}

// NewWeatherSubject 工厂函数:创建天气中心实例
func NewWeatherSubject() *WeatherSubject {
return &WeatherSubject{
observers: make([]Observer, 0),
}
}

// RegisterObserver 注册观察者
func (w *WeatherSubject) RegisterObserver(observer Observer) {
if observer == nil {
fmt.Println("Golang: 观察者实例不可为nil")
return
}
w.mu.Lock()
defer w.mu.Unlock()
// 避免重复注册
for _, obs := range w.observers {
if obs == observer {
return
}
}
w.observers = append(w.observers, observer)
}

// RemoveObserver 注销观察者
func (w *WeatherSubject) RemoveObserver(observer Observer) {
if observer == nil {
fmt.Println("Golang: 观察者实例不可为nil")
return
}
w.mu.Lock()
defer w.mu.Unlock()
// 查找并移除观察者
for i, obs := range w.observers {
if obs == observer {
w.observers = append(w.observers[:i], w.observers[i+1:]...)
break
}
}
}

// notifyObservers 通知所有观察者(私有方法)
func (w *WeatherSubject) notifyObservers() {
w.mu.RLock()
defer w.mu.RUnlock()
// 遍历观察者,触发更新
for _, observer := range w.observers {
observer.Update(w.weather)
}
}

// SetWeather 更新天气状态,触发通知
func (w *WeatherSubject) SetWeather(weatherInfo string) {
if weatherInfo == "" {
fmt.Println("Golang: 天气信息不可为空")
return
}
w.mu.Lock()
w.weather = weatherInfo
w.mu.Unlock()
fmt.Printf("\nGolang 模拟天气状态变更:%s\n", weatherInfo)
w.notifyObservers()
}

// 具体观察者1:手机APP
type PhoneAppObserver struct{}

func (p *PhoneAppObserver) Update(weatherInfo string) {
fmt.Printf("Golang 手机APP:收到天气更新 - %s,已同步显示\n", weatherInfo)
}

// 具体观察者2:气象看板
type WeatherBoardObserver struct{}

func (w *WeatherBoardObserver) Update(weatherInfo string) {
fmt.Printf("Golang 气象看板:收到天气更新 - %s,已刷新看板\n", weatherInfo)
}

// 客户端测试代码
func main() {
// 初始化被观察者
weatherSubject := NewWeatherSubject()
// 初始化具体观察者
phoneApp := &PhoneAppObserver{}
weatherBoard := &WeatherBoardObserver{}

// 注册观察者
weatherSubject.RegisterObserver(phoneApp)
weatherSubject.RegisterObserver(weatherBoard)

// 模拟天气变更
weatherSubject.SetWeather("晴转多云,气温18-25℃")

// 注销观察者
weatherSubject.RemoveObserver(phoneApp)
fmt.Println("Golang 模拟手机APP注销观察者")

// 再次模拟天气变更
weatherSubject.SetWeather("多云转雨,气温16-22℃,注意携带雨具")
}

2.4 C++ 实现(抽象类+多态,经典面向对象实现)

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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <iostream>
#include <vector>
#include <string>
#include <mutex>
using namespace std;

// 抽象观察者类(纯虚函数定义接口)
class Observer {
public:
virtual ~Observer() = default; // 虚析构函数,避免多态场景内存泄漏
/// <summary>
/// 接收被观察者通知,执行更新逻辑
/// </summary>
/// <param name="weatherInfo">天气信息</param>
virtual void Update(const string& weatherInfo) = 0; // 纯虚函数
};

// 被观察者(主题):天气中心
class WeatherSubject {
private:
vector<Observer*> observers; // 存储观察者指针列表
string currentWeather; // 当前天气状态
mutex mtx; // 互斥锁,保证并发安全
public:
~WeatherSubject() {
// 释放观察者指针,避免内存泄漏
for (Observer* obs : observers) {
delete obs;
}
observers.clear();
}

/// <summary>
/// 注册观察者
/// </summary>
/// <param name="observer">观察者指针</param>
void RegisterObserver(Observer* observer) {
if (observer == nullptr) {
throw invalid_argument("观察者实例不可为nullptr");
}
lock_guard<mutex> lock(mtx);
// 避免重复注册
for (Observer* obs : observers) {
if (obs == observer) {
return;
}
}
observers.push_back(observer);
}

/// <summary>
/// 注销观察者
/// </summary>
/// <param name="observer">观察者指针</param>
void RemoveObserver(Observer* observer) {
if (observer == nullptr) {
throw invalid_argument("观察者实例不可为nullptr");
}
lock_guard<mutex> lock(mtx);
// 查找并移除观察者
for (auto it = observers.begin(); it != observers.end(); ++it) {
if (*it == observer) {
delete* it; // 释放观察者内存
observers.erase(it);
break;
}
}
}

/// <summary>
/// 通知所有观察者(私有方法)
/// </summary>
void NotifyObservers() {
lock_guard<mutex> lock(mtx);
for (Observer* obs : observers) {
obs->Update(currentWeather);
}
}

/// <summary>
/// 更新天气状态,触发通知
/// </summary>
/// <param name="weatherInfo">新的天气信息</param>
void SetWeather(const string& weatherInfo) {
if (weatherInfo.empty()) {
throw invalid_argument("天气信息不可为空");
}
currentWeather = weatherInfo;
cout << "\nC++ 模拟天气状态变更:" << weatherInfo << endl;
NotifyObservers();
}
};

// 具体观察者1:手机APP
class PhoneAppObserver : public Observer {
public:
void Update(const string& weatherInfo) override {
cout << "C++ 手机APP:收到天气更新 - " << weatherInfo << ",已同步显示" << endl;
}
};

// 具体观察者2:气象看板
class WeatherBoardObserver : public Observer {
public:
void Update(const string& weatherInfo) override {
cout << "C++ 气象看板:收到天气更新 - " << weatherInfo << ",已刷新看板" << endl;
}
};

// 客户端测试代码
int main() {
try {
// 初始化被观察者
WeatherSubject* weatherSubject = new WeatherSubject();

// 初始化具体观察者并注册
Observer* phoneApp = new PhoneAppObserver();
Observer* weatherBoard = new WeatherBoardObserver();
weatherSubject->RegisterObserver(phoneApp);
weatherSubject->RegisterObserver(weatherBoard);

// 模拟天气变更
weatherSubject->SetWeather("晴转多云,气温18-25℃");

// 注销观察者
weatherSubject->RemoveObserver(phoneApp);
cout << "C++ 模拟手机APP注销观察者" << endl;

// 再次模拟天气变更
weatherSubject->SetWeather("多云转雨,气温16-22℃,注意携带雨具");

// 释放被观察者内存
delete weatherSubject;
}
catch (const exception& e) {
cout << "C++ 执行异常:" << e.what() << endl;
}
return 0;
}

2.5 纯C语言实现(结构体+函数指针,模拟面向对象)

纯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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

// 定义最大天气信息长度,避免内存溢出
#define MAX_WEATHER_LEN 128
// 定义最大观察者数量,适配资源受限场景
#define MAX_OBSERVERS 10

// 抽象观察者:结构体+函数指针模拟接口
typedef struct {
// 更新方法:接收天气信息,执行更新逻辑
void (*update)(void*, const char*);
// 观察者私有数据(可选)
void* data;
} Observer;

// 被观察者(主题):天气中心
typedef struct {
Observer* observers[MAX_OBSERVERS]; // 观察者数组(固定长度,适配嵌入式)
int observer_count; // 已注册的观察者数量
char current_weather[MAX_WEATHER_LEN]; // 当前天气状态
pthread_mutex_t mutex; // 互斥锁,保证并发安全
// 被观察者方法:注册、注销、通知
void (*register_observer)(void*, Observer*);
void (*remove_observer)(void*, Observer*);
void (*notify_observers)(void*);
void (*set_weather)(void*, const char*);
} WeatherSubject;

// 具体观察者更新方法1:手机APP
void phone_app_update(void* observer, const char* weather_info) {
(void)observer; // 未使用观察者私有数据,仅占位
printf("C 手机APP:收到天气更新 - %s,已同步显示\n", weather_info);
}

// 具体观察者更新方法2:气象看板
void weather_board_update(void* observer, const char* weather_info) {
(void)observer;
printf("C 气象看板:收到天气更新 - %s,已刷新看板\n", weather_info);
}

// 被观察者方法:注册观察者
void weather_subject_register(void* subject, Observer* observer) {
if (subject == NULL || observer == NULL || observer->update == NULL) {
printf("C: 被观察者或观察者实例无效\n");
return;
}
WeatherSubject* sub = (WeatherSubject*)subject;
pthread_mutex_lock(&sub->mutex);

// 检查是否达到最大观察者数量,是否重复注册
if (sub->observer_count >= MAX_OBSERVERS) {
printf("C: 观察者数量已达上限,无法注册\n");
pthread_mutex_unlock(&sub->mutex);
return;
}
for (int i = 0; i < sub->observer_count; i++) {
if (sub->observers[i] == observer) {
printf("C: 观察者已注册,无需重复操作\n");
pthread_mutex_unlock(&sub->mutex);
return;
}
}
// 注册观察者
sub->observers[sub->observer_count++] = observer;
pthread_mutex_unlock(&sub->mutex);
}

// 被观察者方法:注销观察者
void weather_subject_remove(void* subject, Observer* observer) {
if (subject == NULL || observer == NULL) {
printf("C: 被观察者或观察者实例无效\n");
return;
}
WeatherSubject* sub = (WeatherSubject*)subject;
pthread_mutex_lock(&sub->mutex);

// 查找并移除观察者
int index = -1;
for (int i = 0; i < sub->observer_count; i++) {
if (sub->observers[i] == observer) {
index = i;
break;
}
}
if (index == -1) {
printf("C: 未找到该观察者,无法注销\n");
pthread_mutex_unlock(&sub->mutex);
return;
}
// 移动数组,覆盖被移除的观察者
for (int i = index; i < sub->observer_count - 1; i++) {
sub->observers[i] = sub->observers[i + 1];
}
sub->observer_count--;
pthread_mutex_unlock(&sub->mutex);
}

// 被观察者方法:通知所有观察者
void weather_subject_notify(void* subject) {
if (subject == NULL) {
printf("C: 被观察者实例无效\n");
return;
}
WeatherSubject* sub = (WeatherSubject*)subject;
pthread_mutex_lock(&sub->mutex);

// 遍历所有观察者,触发更新方法
for (int i = 0; i < sub->observer_count; i++) {
sub->observers[i]->update(sub->observers[i], sub->current_weather);
}
pthread_mutex_unlock(&sub->mutex);
}

// 被观察者方法:更新天气状态,触发通知
void weather_subject_set_weather(void* subject, const char* weather_info) {
if (subject == NULL || weather_info == NULL || strlen(weather_info) == 0) {
printf("C: 被观察者实例无效或天气信息为空\n");
return;
}
WeatherSubject* sub = (WeatherSubject*)subject;
pthread_mutex_lock(&sub->mutex);

// 复制天气信息,避免野指针
strncpy(sub->current_weather, weather_info, MAX_WEATHER_LEN - 1);
sub->current_weather[MAX_WEATHER_LEN - 1] = '\0';
pthread_mutex_unlock(&sub->mutex);

printf("\nC 模拟天气状态变更:%s\n", sub->current_weather);
weather_subject_notify(sub);
}

// 创建观察者实例
Observer* observer_create(void (*update)(void*, const char*), void* data) {
if (update == NULL) {
printf("C: 观察者更新方法不可为NULL\n");
return NULL;
}
Observer* observer = (Observer*)malloc(sizeof(Observer));
if (observer == NULL) {
printf("C: 内存分配失败,无法创建观察者\n");
return NULL;
}
observer->update = update;
observer->data = data;
return observer;
}

// 创建被观察者实例
WeatherSubject* weather_subject_create() {
WeatherSubject* subject = (WeatherSubject*)malloc(sizeof(WeatherSubject));
if (subject == NULL) {
printf("C: 内存分配失败,无法创建被观察者\n");
return NULL;
}
// 初始化观察者数组和计数
memset(subject->observers, 0, sizeof(subject->observers));
subject->observer_count = 0;
// 初始化互斥锁
pthread_mutex_init(&subject->mutex, NULL);
// 绑定被观察者方法
subject->register_observer = weather_subject_register;
subject->remove_observer = weather_subject_remove;
subject->notify_observers = weather_subject_notify;
subject->set_weather = weather_subject_set_weather;
return subject;
}

// 释放观察者内存
void observer_destroy(Observer* observer) {
if (observer != NULL) {
free(observer);
observer = NULL;
}
}

// 释放被观察者内存
void weather_subject_destroy(WeatherSubject* subject) {
if (subject != NULL) {
pthread_mutex_destroy(&subject->mutex);
free(subject);
subject = NULL;
}
}

// 客户端测试代码
int main() {
// 1. 创建被观察者(天气中心)
WeatherSubject* weather_subject = weather_subject_create();
if (weather_subject == NULL) return -1;

// 2. 创建具体观察者
Observer* phone_app = observer_create(phone_app_update, NULL);
Observer* weather_board = observer_create(weather_board_update, NULL);
if (phone_app == NULL || weather_board == NULL) {
observer_destroy(phone_app);
observer_destroy(weather_board);
weather_subject_destroy(weather_subject);
return -1;
}

// 3. 注册观察者
weather_subject->register_observer(weather_subject, phone_app);
weather_subject->register_observer(weather_subject, weather_board);

// 4. 模拟天气变更
weather_subject->set_weather(weather_subject, "晴转多云,气温18-25℃");

// 5. 注销观察者
weather_subject->remove_observer(weather_subject, phone_app);
printf("C 模拟手机APP注销观察者\n");

// 6. 再次模拟天气变更
weather_subject->set_weather(weather_subject, "多云转雨,气温16-22℃,注意携带雨具");

// 7. 释放内存
observer_destroy(phone_app);
observer_destroy(weather_board);
weather_subject_destroy(weather_subject);
return 0;
}

三、观察者模式的优缺点

观察者模式的核心价值是“解耦对象间的联动逻辑,实现状态同步的自动化”,其优缺点均围绕这一核心展开。在实际开发中,需结合业务场景的复杂度、联动规模和性能要求,权衡使用,避免过度设计或滥用,确保既发挥其核心优势,又规避潜在问题。

3.1 核心优点

  • 解耦性极强,符合开闭原则:被观察者与观察者完全解耦,两者仅通过抽象接口通信,被观察者无需知晓具体观察者的实现,观察者也无需关心被观察者的内部逻辑;新增观察者时,无需修改被观察者代码,扩展成本低。

  • 实现状态联动自动化:被观察者状态变更时,所有注册的观察者会被自动通知并更新,无需手动触发,减少代码冗余,提升开发效率,尤其适用于多对象联动的场景。

  • 观察者可灵活扩展:同一被观察者可注册多个不同的观察者,实现不同的业务逻辑(如天气变更同时触发APP通知、看板更新、短信推送),且观察者之间相互独立,互不影响。

  • 职责单一,代码清晰:被观察者专注于状态管理和通知触发,观察者专注于接收通知并执行自身业务逻辑,符合“单一职责原则”,代码结构清晰,便于维护和迭代。

  • 支持广播通信:被观察者的通知可广播给所有注册的观察者,无需逐一调用,适合需要“一对多”联动的场景(如消息通知、系统告警)。

3.2 主要缺点

  • 观察者过多时,通知效率下降:当被观察者注册的观察者数量过多时,状态变更后通知所有观察者会产生一定的性能开销,导致通知延迟,尤其在高频状态变更场景下更为明显。

  • 可能导致循环依赖:若观察者与被观察者之间相互引用,可能形成循环依赖,导致内存泄漏(如C++、C语言中未及时释放指针,Python中循环引用未被GC回收)。

  • 通知顺序不可控:默认情况下,被观察者会按注册顺序通知观察者,若业务逻辑依赖通知顺序,需额外设计排序机制,增加代码复杂度。

  • 调试难度增加:状态变更的联动链路较长,当出现更新异常时,需逐一排查被观察者和所有观察者的逻辑,定位问题的难度提升,增加调试成本。

  • 可能出现“无效通知”:若观察者仅关注部分状态变更,而被观察者的所有状态变更都会触发通知,会导致观察者接收无效通知,浪费系统资源。

四、观察者模式的使用场景

观察者模式的核心适用场景是“存在一对多对象依赖,且需要在被观察者状态变更时,自动同步所有依赖对象的状态”的业务场景。以下结合具体场景及典型实战案例,帮助开发者快速判断是否适用,实现精准落地,避免滥用或错用。

4.1 核心适用场景

  • 消息通知场景:系统中的消息推送、告警通知、邮件/短信发送等,如用户注册成功后,触发短信通知、邮件验证、积分赠送等多个操作,通过观察者模式实现联动。

  • 状态同步场景:多个组件需要同步同一状态,如电商平台的商品库存变更,同步更新商品详情页、购物车、订单系统的库存显示,避免数据不一致。

  • 事件监听场景:GUI界面的事件响应(如按钮点击、鼠标移动)、系统事件的监听(如日志记录、性能监控),通过观察者模式触发对应的事件处理逻辑。

  • 发布-订阅场景:发布者(被观察者)发布消息,订阅者(观察者)接收消息并处理,如消息队列的发布订阅模式、公众号的推文推送,本质是观察者模式的延伸。

  • 数据更新同步场景:数据库数据变更后,同步更新缓存、索引、统计报表等,如用户信息修改后,同步更新Redis缓存、用户画像统计数据。

  • 插件化扩展场景:系统插件的注册与触发,如IDE的插件机制,插件注册到主程序(被观察者),主程序触发特定事件时,所有插件(观察者)执行对应的逻辑。

4.2 典型实战案例

  • 天气预警系统:本文实现的案例,天气中心(被观察者)推送天气变更,手机APP、气象看板、短信通知(观察者)同步更新,实现多终端天气信息同步。

  • 电商订单状态变更:订单状态从“待支付”变为“已支付”时,触发库存扣减、物流创建、积分增加、消息通知等多个操作,每个操作作为观察者,接收订单状态变更通知并执行。

  • GUI界面事件处理:如桌面应用的按钮点击事件,按钮(被观察者)被点击后,通知所有注册的事件处理器(观察者),执行弹窗、页面跳转、数据提交等逻辑。

  • 消息队列发布订阅:如RabbitMQ的Topic交换机,发布者发布消息(被观察者),所有订阅该主题的消费者(观察者)接收消息并处理,实现消息的广播与解耦。

  • 日志收集系统:系统中各模块(被观察者)产生日志时,通知日志收集器(观察者),日志收集器统一处理日志(存储、分析、告警),无需各模块单独处理日志逻辑。

五、总结

观察者模式的核心是“定义一对多依赖,实现状态变更的自动通知与同步更新”,它是“单一职责原则”和“开闭原则”的典型落地方式,通过抽象接口解耦被观察者与观察者,让两者专注于自身核心职责,大幅提升代码的灵活性、可扩展性和可维护性。其本质是“封装联动逻辑,实现自动化同步”,避免了对象间的直接耦合,简化了多对象联动的实现。

从多语言实现来看,尽管各语言的语法特性、设计理念差异显著,但核心逻辑高度统一,且均能适配自身的语言特性,完整实现观察者模式的核心价值:

  • 面向对象语言(C#、C++):通过接口/抽象类严格遵循观察者模式的四大角色,依托多态特性实现解耦,代码结构规范、可维护性强,适配企业级系统和高性能场景;

  • 动态语言(Python):利用鸭子类型简化接口定义,无需显式声明抽象接口,语法简洁灵活,依托GC自动管理内存,适配快速开发、轻量级项目场景;

  • Go语言:以“接口为核心”,通过接口定义契约,结构体实现具体逻辑,结合读写锁保证并发安全,代码极简高效,贴合高并发、高性能的后端开发需求;

  • 纯C语言:通过结构体+函数指针模拟面向对象特性,手动封装数据和行为,依托互斥锁保证并发安全,虽代码冗余,但底层可控性强,适配嵌入式、底层开发等资源受限场景,完美还原观察者模式“解耦联动”的核心思想。

在工程实践中,使用观察者模式需把握三个核心原则:一是判断业务场景是否存在“一对多”的联动需求,是否需要自动同步状态,简单的一对一联动无需引入观察者模式;二是控制观察者的数量,避免过多观察者导致通知效率下降,高频状态变更场景可优化为异步通知;三是避免循环依赖,合理管理对象生命周期,防止内存泄漏。

总体而言,观察者模式是处理多对象联动、状态同步场景的核心设计工具,尤其在消息通知、事件监听、发布订阅等场景中价值显著。理解观察者模式的核心,不在于照搬代码结构,而在于掌握“解耦联动逻辑、实现自动化同步”的设计思路,合理运用可让代码结构更清晰、职责更单一、扩展更灵活,提升系统的可维护性和复用性。