概述
观察者模式主要定义对象之间的一种一对多的依赖关系,当一个对象(被观察者)的状态发生改变时,所有依赖他的对象(观察者)都得到通知并进行相应的操作;这里reader(派生自obsever)从media(派生自subject)订阅新闻,当有新闻产生时media就会调用notify通知(调用对应观察者的update方法)所有订阅该新闻的reader都拿到新闻;
1. subject 定义及实现
///< 定义
#ifndef _SUBJECT_H
#define _SUBJECT_H
#include "ulist.h"
#include"observer.h"
struct subject_vmt;
struct subject {
struct subject_vmt* vptr;
//struct observer* observers[10];
struct list_head list_obs;
void (*attach_observer)(struct subject* pthis, struct observer* pobs);
void (*detach_observer)(struct subject* pthis, struct observer* pobs);
void (*notify_observers)(struct subject* pthis);
};
struct subject_vmt {
void (*attach_observer_virtual)(struct subject* pthis, struct observer* pobs);
void (*detach_observer_virtual)(struct subject* pthis, struct observer* pobs);
void (*notify_observers_virtual)(struct subject* pthis);
};
extern void subject_init(struct subject* pthis);
#endif // _SUBJECT_H
///< 实现
#include<stdio.h>
#include<stdlib.h>
#include"subject.h"
#include"observer.h"
#include"ulist.h"
void attach_observer_virtual(struct subject* pthis, struct observer* pobs)
{
list_add(&pobs->node, &pthis->list_obs);
}
void detach_observer_virtual(struct subject* pthis, struct observer* pobs)
{
struct observer* temp, *guard;
list_for_each_entry_safe(temp, guard, &pthis->list_obs, node) {
if (temp == pobs) {
printf("detach a observer on observers list.\n");
list_del(&temp->node);
}
}
}
void notify_observers_virtual(struct subject* pthis)
{
struct observer* temp;
list_for_each_entry(temp, &pthis->list_obs, node) {
temp->update(temp, pthis);
}
}
void attach_observer_subject(struct subject* pthis, struct observer* pobs)
{
pthis->vptr->attach_observer_virtual(pthis, pobs);
}
void detach_observer_subject(struct subject* pthis, struct observer* pobs)
{
pthis->vptr->detach_observer_virtual(pthis, pobs);
}
void notify_observers_subject(struct subject* pthis)
{
pthis->vptr->notify_observers_virtual(pthis);
}
void subject_init(struct subject* pthis)
{
static struct subject_vmt svmt = {
.attach_observer_virtual = attach_observer_virtual,
.detach_observer_virtual = detach_observer_virtual,
.notify_observers_virtual = notify_observers_virtual,
};
INIT_LIST_HEAD(&pthis->list_obs);
pthis->vptr = &svmt;
pthis->attach_observer = attach_observer_subject;
pthis->detach_observer = detach_observer_subject;
pthis->notify_observers = notify_observers_subject;
}
struct subject* construct_subject(void)
{
struct subject* pthis = malloc(sizeof(*pthis));
subject_init(pthis);
return pthis;
}
void destruct_subject(struct subject* pthis)
{
free(pthis);
}
2. observer 定义及实现
///< 定义
#include"ulist.h"
///< interface class
struct subject;
struct observer_vmt;
struct observer {
const struct observer_vmt* vptr;
struct list_head node;
void (*update)(struct observer* pthis, struct subject* psub);
};
struct observer_vmt {
void (*update_virtual)(struct observer* pthis, struct subject* psub);
};
extern void observer_init(struct observer* pthis);
#endif // _OBSERVER_H
///< 实现
#include<stdio.h>
#include<stdlib.h>
#include"observer.h"
#include"subject.h"
#include"ulist.h"
void update_observer(struct observer* pthis, struct subject* psub)
{
pthis->vptr->update_virtual(pthis, psub);
}
void observer_init(struct observer* pthis)
{
static const struct observer_vmt ovmt = {
.update_virtual = NULL, ///< must override by derived class
};
INIT_LIST_HEAD(&pthis->node);
pthis->vptr = &ovmt;
pthis->update = update_observer;
}
3. media 定义及实现
///< 定义
#ifndef _MEDIA_H
#define _MEDIA_H
#include"subject.h"
struct media {
struct subject super;
char news[1024];
void (*set_news)(struct media* pthis, char* news);
char* (*get_news)(struct media* pthis);
};
extern struct media* construct_media(void);
extern void destruct_media(struct media* pthis);
#endif // _MEDIA_H
///< 实现
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"observer.h"
#include"subject.h"
#include"media.h"
static void set_news(struct media* pthis, char* news)
{
strncpy(pthis->news, news, 1023);
struct subject* ps = (struct subject*)pthis;
ps->notify_observers(ps);
}
static char* get_news(struct media* pthis)
{
return pthis->news;
}
void media_init(struct media* pthis)
{
subject_init(&pthis->super);
pthis->set_news = set_news;
pthis->get_news = get_news;
}
struct media* construct_media(void)
{
struct media* pthis = malloc(sizeof(*pthis));
memset(pthis, 0, sizeof(*pthis));
media_init(pthis);
return pthis;
}
void destruct_media(struct media* pthis)
{
free(pthis);
}
4. reader 定义及实现
///< 定义
#ifndef _READER_H
#define _READER_H
#include "observer.h"
#include "subject.h"
struct reader {
struct observer super;
char name[10];
void (*update)(struct observer* pthis, struct subject* psub);
};
extern struct reader* construct_reader(char* name);
extern void destruct_reader(struct reader* pthis);
#endif // _READER_H
///< 实现
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"ulist.h"
#include"subject.h"
#include"observer.h"
#include"media.h"
#include"reader.h"
static void reader_update_virtual(struct observer* pthis, struct subject* psub)
{
struct media* pm = (struct media*)psub;
printf("reader[%s] get news from media: %s\n", ((struct reader*)pthis)->name, pm->get_news(pm));
}
void reader_init(struct reader* pthis, char* pname)
{
static struct observer_vmt rvmt = {
.update_virtual = reader_update_virtual,
};
observer_init(&pthis->super);
pthis->super.vptr = &rvmt;
pthis->update = reader_update_virtual;
strncpy(pthis->name, pname, 10);
}
struct reader* construct_reader(char* name)
{
struct reader* pthis = malloc(sizeof(*pthis));
reader_init(pthis, name);
return pthis;
}
void destruct_reader(struct reader* pthis)
{
free(pthis);
}
5. 测试方法
#include<stdio.h>
#include"subject.h"
#include"observer.h"
#include"media.h"
#include"reader.h"
int main()
{
struct observer* po1 = (struct observer*)construct_reader("xxdk001");
struct observer* po2 = (struct observer*)construct_reader("xxdk002");
struct observer* po3 = (struct observer*)construct_reader("xxdk003");
struct subject* ps = (struct subject*)construct_media();
ps->attach_observer(ps, po1);
ps->attach_observer(ps, po2);
ps->attach_observer(ps, po3);
struct media* pm = (struct media*)ps;
pm->set_news(pm, "hello buaa!");
ps->detach_observer(ps, po3);
pm->set_news(pm, "stragetic focus!");
destruct_reader((struct reader*)po1);
destruct_reader((struct reader*)po2);
destruct_reader((struct reader*)po3);
destruct_media(pm);
}