观察者模式(C语言实现)

一. 概述

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

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。