Skip to content

Commit 6be0ab5

Browse files
author
Jarry
committed
add observer for c
1 parent 723e29b commit 6be0ab5

File tree

8 files changed

+384
-2
lines changed

8 files changed

+384
-2
lines changed

observer-pattern/README.md

Lines changed: 153 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# 【观察者设计模式详解】Java/JS/Go/Python/TS不同语言实现
1+
# 【观察者设计模式详解】C/Java/JS/Go/Python/TS不同语言实现
22

33
# 简介
44
观察者模式(Observer Pattern)是一种行为型模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
@@ -23,7 +23,7 @@
2323
<img src="../docs/uml/observer-pattern.png">
2424

2525

26-
# 代码
26+
# Java代码
2727

2828
## 观察者接口
2929
```java
@@ -149,5 +149,156 @@ public class ConcreteSubject extends Subject {
149149
concreteSubject.notify("hello, this is broadcast.");
150150

151151
```
152+
153+
# Python代码
154+
155+
## 观察者接口
156+
```py
157+
# ObserverAPI.py 观察者抽象父类,定义一些公共方法
158+
class ObserverAPI:
159+
160+
def __init__(self, name):
161+
self.name = name
162+
163+
# 观察者发出更新通知,观察者自行监听
164+
def update(self, content):
165+
print(self.__class__.__name__ + '::update() [content = ' + content + ']')
166+
167+
def set_name(self, name):
168+
self.name = name
169+
```
170+
171+
## 具体观察者
172+
```py
173+
# ConcreteObserver.py 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
174+
# 不同的观察者也可以对应多个主题
175+
from src.ObserverAPI import ObserverAPI
176+
177+
# 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
178+
# 不同的观察者也可以对应多个主题
179+
180+
181+
class ConcreteObserver(ObserverAPI):
182+
# 给观察者绑定主题,同时把观察者添加到主题列表
183+
def __init__(self, subject, name):
184+
ObserverAPI.__init__(self, name)
185+
186+
# python3支持的父类调用
187+
# super(ConcreteObserver, self).__init__(name)
188+
# super().__init__(name)
189+
190+
self.subject = subject
191+
subject.register(self)
192+
193+
# 观察者发出更新通知,不用单独告诉订阅者,由订阅者自行监听
194+
def update(self, content):
195+
print(self.__class__.__name__ + '::update() [subject.name = ' +
196+
self.subject.name + ' content = ' + content + ']')
197+
```
198+
199+
```py
200+
# ConcreteObserver2.py 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
201+
# 不同的观察者可以对应不同的主题。
202+
from src.ObserverAPI import ObserverAPI
203+
204+
205+
# 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
206+
# 不同的观察者可以对应不同的主题。
207+
class ConcreteObserver2(ObserverAPI):
208+
# 这里没有在构造器就绑定某个主题,而是从客户角度去注册观察者
209+
# 观察者发出更新通知,观察者自行监听
210+
211+
# def update(self, content):
212+
# print(self.__class__.__name__ + '::update() [content = ' + content +']')
213+
214+
pass
215+
```
216+
217+
## 抽象主题类
218+
```py
219+
# Subject.py 定义抽象主题类或者接口,供具体主题类继承
220+
class Subject:
221+
222+
def __init__(self, name):
223+
self.name = name
224+
self.observers = []
225+
226+
def get_name(self):
227+
return self.name
228+
229+
def set_name(self, name):
230+
self.name = name
231+
232+
def register(self, observer):
233+
print(self.__class__.__name__ + '::register() [observer = ' +
234+
observer.__class__.__name__ + ']')
235+
236+
self.observers.append(observer)
237+
238+
def remove(self, observer):
239+
self.observers.remove(observer)
240+
241+
# 通知由具体类来实现逻辑
242+
def notify(self, name):
243+
pass
244+
```
245+
246+
## 具体主题类
247+
```py
248+
// ConcreteSubject.py 观察者主题类,也是发布者,重写具体的通知方法。不同主题可以关联不同的观察者。
249+
from src.Subject import Subject
250+
251+
252+
# 观察者主题类,也是发布者,重写具体的通知方法。不同主题可以关联不同的观察者。
253+
class ConcreteSubject(Subject):
254+
# 不同的主题类有自己的通知方法,批量通知绑定的观察者
255+
def notify(self, content):
256+
print(self.__class__.__name__ + '::notify() [content = ' + content +
257+
']')
258+
for observer in self.observers:
259+
observer.update(content)
260+
```
261+
262+
## 测试调用
263+
```py
264+
import sys
265+
import os
266+
267+
os_path = os.getcwd()
268+
sys.path.append(os_path)
269+
270+
from src.ConcreteSubject import ConcreteSubject
271+
from src.ConcreteObserver import ConcreteObserver
272+
from src.ConcreteObserver2 import ConcreteObserver2
273+
274+
275+
def test():
276+
'''
277+
* 观察者模式应用非常广泛,主要是观察者提前绑定到发布者
278+
* 当发布者发布消息时,批量广播通知,而无需逐一通知
279+
* 观察者监听到消息后自己决定采取哪一种行为
280+
'''
281+
282+
# 定义一个主题,也就是发布者
283+
concrete_subject = ConcreteSubject('subject1')
284+
# 再声明观察者,通过构造器注册到主题上
285+
observer1 = ConcreteObserver(concrete_subject, 'observer1')
286+
# 也可以单独给主题注册一个新的观察者
287+
observer2 = ConcreteObserver2('observer2')
288+
concrete_subject.register(observer2)
289+
# 可以移除观察者对象
290+
# concrete_subject.remove(observer1)
291+
292+
# 主题开始发布新通知,各观察者自动更新
293+
concrete_subject.notify('hello, this is broadcast.')
294+
295+
296+
if __name__ == '__main__':
297+
print(__file__)
298+
print("test start:")
299+
test()
300+
301+
```
302+
152303
## 更多语言版本
153304
不同语言实现设计模式:[https://github.com/microwind/design-pattern](https://github.com/microwind/design-pattern)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include "func.h"
2+
3+
void concrete_observer_set_subject(ConcreteObserver *observer, Subject *subject)
4+
{
5+
observer->subject = subject;
6+
}
7+
8+
// 观察者发出更新通知,不用单独告诉订阅者,由订阅者自行监听
9+
void concrete_observer_update(ConcreteObserver *observer, char *content)
10+
{
11+
printf("\r\n ConcreteObserver::update() [subject->name = %s content = %s]", observer->subject->name, content);
12+
}
13+
14+
// 给观察者绑定主题,同时把观察者添加到主题列表
15+
ConcreteObserver *concrete_observer_constructor(char *name)
16+
{
17+
printf("\r\n concrete_observer_constructor() [构建ConcreteObserver]");
18+
Observer *observer = (Observer *)malloc(sizeof(Observer));
19+
ConcreteObserver *concrete_observer = (ConcreteObserver *)observer;
20+
strncpy(observer->name, name, 50);
21+
concrete_observer->set_subject = &concrete_observer_set_subject;
22+
concrete_observer->update = &concrete_observer_update;
23+
24+
return concrete_observer;
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include "func.h"
2+
3+
void concrete_observer2_set_subject(ConcreteObserver2 *observer, Subject *subject)
4+
{
5+
observer->subject = subject;
6+
}
7+
8+
// 观察者发出更新通知,不用单独告诉订阅者,由订阅者自行监听
9+
void concrete_observer2_update(ConcreteObserver2 *observer, char *content)
10+
{
11+
printf("\r\n ConcreteObserver2::update() [subject->name = %s content = %s]", observer->subject->name, content);
12+
}
13+
14+
// 给观察者绑定主题,同时把观察者添加到主题列表
15+
ConcreteObserver2 *concrete_observer2_constructor(char *name)
16+
{
17+
printf("\r\n concrete_observer2_constructor() [构建ConcreteObserver2]");
18+
Observer *observer = (Observer *)malloc(sizeof(Observer));
19+
ConcreteObserver2 *concrete_observer2 = (ConcreteObserver2 *)observer;
20+
strncpy(observer->name, name, 50);
21+
concrete_observer2->set_subject = &concrete_observer2_set_subject;
22+
concrete_observer2->update = &concrete_observer2_update;
23+
24+
return concrete_observer2;
25+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#include "func.h"
2+
3+
// 观察者主题类,也是发布者,重写具体的通知方法。不同主题可以关联不同的观察者。
4+
5+
void concrete_registry(ConcreteSubject *subject, Observer *observer)
6+
{
7+
printf("\r\n ConcreteSubject::register() [observer = %s]", observer->name);
8+
subject->observers_length += 1;
9+
Observer **new_observers = (Observer **)calloc(subject->observers_length, sizeof(Observer));
10+
// 复制原有数组,并追加新内容到新数组
11+
for (int i = 0; i < subject->observers_length - 1; i++)
12+
{
13+
new_observers[i] = subject->observers[i];
14+
}
15+
new_observers[subject->observers_length - 1] = observer;
16+
free(subject->observers);
17+
// 指向新数组
18+
subject->observers = new_observers;
19+
}
20+
21+
void concrete_remove(ConcreteSubject *subject, Observer *observer)
22+
{
23+
printf("\r\n ConcreteSubject::remove() [observer = %s]", observer->name);
24+
Observer **new_observers = (Observer **)calloc(subject->observers_length - 1, sizeof(Observer));
25+
int new_length = 0;
26+
bool is_removed = false;
27+
for (int i = 0; i < subject->observers_length; i++)
28+
{
29+
// 过滤掉第一个出现的匹配项,达到删除目的
30+
if (is_removed == false && subject->observers[i] == observer)
31+
{
32+
is_removed = true;
33+
continue;
34+
}
35+
new_length++;
36+
new_observers[new_length - 1] = subject->observers[i];
37+
}
38+
free(subject->observers);
39+
// 指向新数组和新长度
40+
subject->observers = new_observers;
41+
subject->observers_length = new_length;
42+
}
43+
44+
// 通知批量各个观察者
45+
void concrete_notify(ConcreteSubject *subject, char *content)
46+
{
47+
printf("\r\n ConcreteSubject::notify() [content = %s]", content);
48+
for (int i = 0; i < subject->observers_length; i++)
49+
{
50+
subject->observers[i]->update(subject->observers[i], content);
51+
}
52+
}
53+
54+
ConcreteSubject *concrete_subject_constructor(char *name)
55+
{
56+
printf("\r\n concrete_subject_constructor() [构建订阅主题]");
57+
Subject *subject = (Subject *)malloc(sizeof(Subject));
58+
ConcreteSubject *concrete_subject = (ConcreteSubject *)subject;
59+
strncpy(concrete_subject->name, name, 50);
60+
concrete_subject->registry = &concrete_registry;
61+
concrete_subject->remove = &concrete_remove;
62+
concrete_subject->notify = &concrete_notify;
63+
return concrete_subject;
64+
}

observer-pattern/c/src/func.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#include <stdio.h>
2+
#include <ctype.h>
3+
#include <stdlib.h>
4+
#include <stdbool.h>
5+
#include <string.h>
6+
7+
typedef struct Subject Subject;
8+
typedef struct Observer Observer;
9+
typedef struct ConcreteSubject ConcreteSubject;
10+
typedef struct ConcreteObserver ConcreteObserver;
11+
typedef struct ConcreteObserver2 ConcreteObserver2;
12+
13+
// 观察者抽象父类,定义一些公共方法
14+
typedef struct Observer
15+
{
16+
char name[50];
17+
Subject *subject;
18+
void (*set_subject)(Observer *observer, Subject *subject);
19+
void (*update)(Observer *observer, char *content);
20+
} Observer;
21+
22+
// 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
23+
typedef struct ConcreteObserver
24+
{
25+
char name[50];
26+
Subject *subject;
27+
void (*set_subject)(ConcreteObserver *observer, Subject *subject);
28+
void (*update)(ConcreteObserver *observer, char *content);
29+
} ConcreteObserver;
30+
ConcreteObserver *concrete_observer_constructor(char *name);
31+
32+
// 具体的观察者实现类2,也可以看成订阅者,关联对应的主题类。
33+
typedef struct ConcreteObserver2
34+
{
35+
char name[50];
36+
Subject *subject;
37+
void (*set_subject)(ConcreteObserver2 *observer, Subject *subject);
38+
void (*update)(ConcreteObserver2 *observer, char *content);
39+
} ConcreteObserver2;
40+
ConcreteObserver2 *concrete_observer2_constructor(char *name);
41+
42+
// 定义抽象主题类或者接口,供具体主题类继承
43+
typedef struct Subject
44+
{
45+
char name[50];
46+
Observer **observers;
47+
int observers_length;
48+
void (*registry)(Subject *subject, Observer *observer);
49+
void (*remove)(Subject *subject, Observer *observer);
50+
void (*notify)(Subject *subject, char *content);
51+
} Subject;
52+
53+
// 观察者主题类,也是发布者,重写具体的通知方法。不同主题可以关联不同的观察者。
54+
typedef struct ConcreteSubject
55+
{
56+
char name[50];
57+
Observer **observers;
58+
int observers_length;
59+
void (*registry)(ConcreteSubject *subject, Observer *observer);
60+
void (*remove)(ConcreteSubject *subject, Observer *observer);
61+
void (*notify)(ConcreteSubject *subject, char *content);
62+
} ConcreteSubject;
63+
ConcreteSubject *concrete_subject_constructor(char *name);

observer-pattern/c/src/observer.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#include "func.h"
2+
3+
// 观察者抽象父类,定义一些公共方法,见head文件

observer-pattern/c/src/subject.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#include "func.h"
2+
3+
// 定义抽象主题类或者接口,供具体主题类继承,见head文件

0 commit comments

Comments
 (0)