一. 概述
Observer 模式要解决的问题为:建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这个“一”的多也能够同步改变。
Sbuject 相当于通知者,它提供依赖于它的观察者Observer 的注册(Attach)和注销(Detach)操作,并且提供了使得依赖于它的所有观察者同步的操作(Notify)。
Observer 相当于观察者,则提供一个Update操作,注意这里的 Observer 的 Update 操作并不在Observer 改变了Subject目标状态的时候就对自己进行更新,这个更新操作要延迟到 Subject 对象发出 Notify 通知所有 Observer 进行修改(调用Update)。
二. 举例
最常见的一个例子就是:对同一组数据进行统计分析时候,我们希望能够提供多种形式的表示(例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据,我们当然需要当数据改变的时候,所有的统计的显示都能够同时改变。
结构关系图如下:
DataSubject : 我们就认为是原始数据。
SheetObserver:就认为是表格,用来显示原始数据用的。
ChartObserver :就认为是图表,也是来显示原始数据的。
代码如下:
abstractClass.h
#ifndef ABSTRACTCLASS_H
#define ABSTRACTCLASS_H
#include <stdlib.h>
#include <stdarg.h>
typedef struct {
size_t size;
void* (*ctor)(void *_self, va_list *params);
void* (*dtor)(void *_self);
} AbstractClass;
#endif
subject.h
#ifndef SUBJECT_H
#define SUBJECT_H
#include <stdlib.h>
#include <stdarg.h>
typedef struct {
size_t size;
void* (*ctor)(void *_self, va_list *params);
void* (*dtor)(void *_self);
void (*attach)(void *_self, void *_obv); // Observer
void (*detach)(void *_self, void *_obv); // Observer
void (*notify)(const void *_self);
void (*setstate)(void *_self, char *_st);
char *(*getstate)(const void *_self);
} Subject;
#endif
dataSubject.h
#ifndef DATASUBJECT_H
#define DATASUBJECT_H
typedef struct {
const void *_;
void *obvs;
char *st;
} _DataSubject;
const void *DataSubject;
#endif
dataSubject.c
#include "subject.h"
#include "datasubject.h"
#include "new.h"
#include "singleList.h"
#include "observer.h"
#include <stdarg.h>
#include <stdlib.h>
#include <assert.h>
static void *dataSubjectCtor(void *_self, va_list *params) {
_DataSubject *self = _self;
self->obvs = New(SingleList);
return self;
}
static void *dataSubjectDtor(void *_self) {
_DataSubject *self = _self;
Delete(self->obvs);
self->obvs = NULL;
return self;
}
static void dataSubjectAttach(void *_self, void *_obv) {
_DataSubject *self = _self;
Insert(self->obvs, _obv);
}
static void dataSubjectDetach(void *_self, void *_obv) {
_DataSubject *self = _self;
Remove(self->obvs, _obv);
}
static void update(void *_obv, va_list *params) {
Observer **obv = _obv;
void *sub = va_arg(*params, void*);
assert(_obv && *obv && (*obv)->update);
(*obv)->update(_obv, sub);
}
static void dataSubjectNotify(const void *_self) {
const _DataSubject *self = _self;
Iterator(self->obvs, update, _self);
}
static void dataSubjectSetState(void *_self, char *_st) {
_DataSubject *self = _self;
self->st = _st;
}
static char *dataSubjectGetState(const void *_self) {
const _DataSubject *self = _self;
return self->st;
}
static const Subject dataSubject = {
sizeof(_DataSubject),
dataSubjectCtor,
dataSubjectDtor,
dataSubjectAttach,
dataSubjectDetach,
dataSubjectNotify,
dataSubjectSetState,
dataSubjectGetState
};
const void *DataSubject = &dataSubject;
observer.h
#ifndef OBSERVER_H
#define OBSERVER_H
#include <stdlib.h>
#include <stdarg.h>
typedef struct {
size_t size;
void* (*ctor)(void* _self, va_list *params);
void* (*dtor)(void *_self);
void (*update)(void *_self, const void *sub); // Subject
void (*printinfo)(const void *_self);
} Observer;
#endif
sheetObserver.h
#ifndef SHEETOBSERVER_H
#define SHEETOBSERVER_H
typedef struct {
const void *_;
char *st;
void *sub;
} _SheetObserver;
const void *SheetObserver;
#endif
sheetObserver.c
#include "observer.h"
#include "sheetobserver.h"
#include "subject.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
static void* sheetObserverCtor(void *_self, va_list *params) {
_SheetObserver *self = _self;
self->sub = va_arg(*params, void*);
const Subject **sub = self->sub;
assert(self->sub && *sub && (*sub)->attach);
(*sub)->attach(self->sub, _self);
return self;
}
static void *sheetObserverDtor(void *_self) {
_SheetObserver *self = _self;
const Subject **sub = self->sub;
assert(self->sub && *sub && (*sub)->detach);
(*sub)->detach(self->sub, _self);
self->sub = NULL;
return self;
}
static void sheetObserverPrintInfo(const void *_self) {
const _SheetObserver *self = _self;
fprintf(stdout, "SheetObserver: %s\n", self->st);
}
static void sheetObserverUpdate(void *_self, const void *_sub) {
_SheetObserver *self = _self;
const Subject * const *sub = _sub;
assert(_sub && *sub && (*sub)->getstate);
self->st = (*sub)->getstate(_sub);
sheetObserverPrintInfo(_self);
}
static const Observer _sheetObserver = {
sizeof(_SheetObserver),
sheetObserverCtor,
sheetObserverDtor,
sheetObserverUpdate,
sheetObserverPrintInfo
};
const void *SheetObserver = &_sheetObserver;
chatObserver.h
#ifndef CHATOBSERVER_H
#define CHATOBSERVER_H
typedef struct {
const void *_;
char *st;
void *sub;
} _ChatObserver;
const void *ChatObserver;
#endif
chatObserver.c
#include "observer.h"
#include "chatobserver.h"
#include "subject.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
static void* chatObserverCtor(void *_self, va_list *params) {
_ChatObserver *self = _self;
self->sub = va_arg(*params, void*);
const Subject **sub = self->sub;
assert(self->sub && *sub && (*sub)->attach);
(*sub)->attach(self->sub, _self);
return self;
}
static void *chatObserverDtor(void *_self) {
_ChatObserver *self = _self;
const Subject **sub = self->sub;
assert(self->sub && *sub && (*sub)->detach);
(*sub)->detach(self->sub, _self);
self->sub = NULL;
return self;
}
static void chatObserverPrintInfo(const void *_self) {
const _ChatObserver *self = _self;
fprintf(stdout, "ChatObserver: %s\n", self->st);
}
static void chatObserverUpdate(void *_self, const void *_sub) {
_ChatObserver *self = _self;
const Subject * const *sub = _sub;
assert(_sub && *sub && (*sub)->getstate);
self->st = (*sub)->getstate(_sub);
chatObserverPrintInfo(_self);
}
static const Observer _chatObserver = {
sizeof(_ChatObserver),
chatObserverCtor,
chatObserverDtor,
chatObserverUpdate,
chatObserverPrintInfo
};
const void *ChatObserver = &_chatObserver;
list.h
#ifndef LIST_H
#define LIST_H
#include <stdarg.h>
#include <stdlib.h>
typedef void (*Print_FN)(void* data);
typedef void (*Handle_FN)(void *node, va_list *params);
typedef struct {
size_t size;
void* (*ctor)(void *_self, va_list *params);
void* (*dtor)(void *_self);
void (*insert)(const void *_self, void *data);
void (*remove)(const void *_self, void *data);
void (*iterator)(const void *_self, Handle_FN handle_fn, va_list *params);
void (*print)(const void *_self, Print_FN print_fn);
} List;
#endif
singleList.h
#ifndef SINGLELIST_H
#define SINGLELIST_H
typedef struct _Node {
void *data;
struct _Node *next;
} Node;
typedef struct {
const void *_;
Node *head;
} _SingleList;
extern const void *SingleList;
#endif
singleList.c
#include "list.h"
#include "singleList.h"
#include "new.h"
#include <stdlib.h>
static void *singleListCtor(void *_self, va_list *params) {
_SingleList *self = _self;
self->head = (Node*)calloc(1, sizeof(Node));
return self;
}
static void *singleListDtor(void *_self) {
_SingleList *self = _self;
Node **p = &self->head;
while ((*p) != NULL) {
Node *node = *p;
*p = node->next;
free(node);
}
return self;
}
static void singleListInsert(const void *_self, void *data) {
const _SingleList *self = _self;
Node *node = (Node*)calloc(1, sizeof(Node));
Node **p = (Node **)&self->head;
for (; (*p) != NULL; p = &(*p)->next) {
;
}
node->data = data;
node->next = *p;
*p = node;
}
static void singleListRemove(const void *_self, void *data) {
const _SingleList *self = _self;
Node **p = (Node **)&self->head;
while ((*p) != NULL) {
Node *node = *p;
if (node->data == data) {
*p = node->next;
} else {
p = &(*p)->next;
}
}
}
static void singleListIterator(const void *_self, Handle_FN handle_fn, va_list *params) {
const _SingleList *self = _self;
Node **p = &self->head->next;
for (; (*p) != NULL; p = &(*p)->next) {
va_list args;
va_copy(args, *params);
handle_fn((*p)->data, &args);
va_end(args);
}
}
static void singleListPrint(const void *_self, Print_FN print_fn) {
const _SingleList *self = _self;
Node **p = &self->head->next;
while ((*p) != NULL) {
print_fn((*p)->data);
p = &(*p)->next;
}
}
static const List _singleList = {
sizeof(_SingleList),
singleListCtor,
singleListDtor,
singleListInsert,
singleListRemove,
singleListIterator,
singleListPrint,
};
const void *SingleList = &_singleList;
new.h
#ifndef NEW_H
#define NEW_H
#include "list.h"
void *New(const void *_class, ...);
void Delete(void *_class);
void SetState(void *_subject, char *_st);
void Notify(const void *_subject);
void Update(void *_observer, const void *_subject);
void Insert(void *_list, void *_item);
void Remove(void *_list, void *_item);
void Iterator(const void *list, Handle_FN handle_fn, ...);
void Print(void *_list, Print_FN print_fn);
#endif
new.c
#include "new.h"
#include "abstractClass.h"
#include "singleList.h"
#include "subject.h"
#include "observer.h"
#include <assert.h>
void *New(const void *_class, ...) {
const AbstractClass *class = _class;
void *p = calloc(1, class->size);
assert(p);
*(const AbstractClass **)p = class;
if (class->ctor) {
va_list params;
va_start(params, _class);
p = class->ctor(p, ¶ms);
va_end(params);
}
return p;
}
void Delete(void *_class) {
const AbstractClass **class = _class;
if (_class && *class && (*class)->dtor) {
_class = (*class)->dtor(_class);
}
free(_class);
}
void SetState(void *_subject, char *_st) {
Subject **subject = _subject;
if (_subject && *subject && (*subject)->setstate) {
(*subject)->setstate(_subject, _st);
}
}
void Notify(const void *_subject) {
const Subject * const *subject = _subject;
if (_subject && *subject && (*subject)->notify) {
(*subject)->notify(_subject);
}
}
void Update(void *_observer, const void *_subject) {
Observer **observer = _observer;
if (_observer && *observer && (*observer)->update) {
(*observer)->update(_observer, _subject);
}
}
void Insert(void *_list, void *_item) {
((const List*)SingleList)->insert(_list, _item);
}
void Remove(void *_list, void *_item) {
((const List*)SingleList)->remove(_list, _item);
}
void Iterator(const void *_list, Handle_FN handle_fn, ...) {
va_list params;
va_start(params, handle_fn);
((const List*)SingleList)->iterator(_list, handle_fn, ¶ms);
va_end(params);
}
void Print(void *_list, Print_FN print_fn) {
((const List*)SingleList)->print(_list, print_fn);
}
main.c
#include "new.h"
#include "datasubject.h"
#include "sheetobserver.h"
#include "chatobserver.h"
int main(int argc, char *argv[]) {
void *sub = New(DataSubject);
void *o1 = New(SheetObserver, sub);
void *o2 = New(ChatObserver, sub);
SetState(sub, "old data");
Notify(sub);
SetState(sub, "new data");
Notify(sub);
Update(o1, sub);
return 0;
}
图片来源:http://blog.csdn.net/hmsiwtv/article/details/9626967