面向对象编程 (object-oriented programming),是一种设计思想 或者架构风格,而非仅仅是编码方式,OOP程序也并不一定要用OOP语言来写。
OOP拥有封装,继承与多态三大特性,但 $OOP \not= 封装+继承+多态$。
封装 是想把一段逻辑/概念抽象出来做到”相对独立”。多态 是指让一组Object表达同一概念,并展现不同的行为。继承 是希望通过类型的is-a关系来实现代码的复用。
在c语言里运用面向对象 c语言有哪些方法来支持OOP编程呢?
struct结构体,可以将对象的状态和行为封装在一起。
函数 当然也可以封装,实现简洁的接口与复杂的内部隐藏,函数指针 关联对象的行为。
static关键字可以控制变量与函数的作用域,避免命名冲突与链接错误。
const关键字约束一些变量的行为。
类型转换 ,void类型转换,结构体类型转换一定程度上可以模拟多态与继承。
一些命名规范 也可以起到访问控制的说明。
#define宏语法实现的代码复用。
首先看一个基础的的栈实现方式:
stack.h头文件
1 2 3 4 5 6 7 #ifndef _STACK_H_ #define _STACK_H_ bool push (int iVal) ;bool pop (int *pRet) ;#endif
stack.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 #include <stdio.h> #include "stack.h" int buf[16 ];int top = 0 ;bool isStackFull () { return top == sizeof (buf) / sizeof (int ); } bool isStackEmpty () { return top == 0 } bool push(int iVal) { if (isStackFull()) return false ; buf[top++] = val; return true ; } bool pop (int *pRet) { if (isStackEmpty()) return false ; *pRet = buf[--top]; return true ; }
使用面向对象的思想来优化这个栈,并且增加来了两个检查功能,第一个检查:栈中存储的值要在一定的范围内,第二个检查:每次push到栈中的数据必须比上一次的值大。
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 #ifndef _STACK_H_ #define _STACK_H_ #ifdef __cplusplus extern "C" {#endif typedef struct Validator { bool (* const validate) (struct Validator *pThis, int val); void * const pData; } typedef struct { const int min; const int max; } Range; typedef struct { int previousValue; } PreviousValue; typedef struct { int top; const size_t size; int * const pBuf; Validator * const pValidator; } Stack; #define newStack(buf) { \ 0, sizeof(buf) / sizeof(int), (buf), \ NULL \ } #define rangeValidator(pRange) { \ validateRange, \ pRange \ } #define previousValidator(pPrevious) { \ validatePrevious, \ pPrevious \ } #define newStackWithValidator(buf, pValidator) { \ 0, sizeof(buf) / sizeof(int), (buf), \ pValidator \ } bool validateRange (Validator *pThis, int iVal) ;bool validatePrevious (Validator *pThis, int iVal) ;#ifdef __cplusplus } #endif #endif
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 #include <stdbool.h> #include "stack.h" static bool isStackFull (const Stack *p) { return p->top == p->size; } static bool isStackEmpty (const Stack *p) { return p->top == 0 ; } bool validateRange (Validator *pThis, int iVal) { Range *pRange = (Range *)(pThis->pData); return pRange->min <= iVal && val <= pRange->max; } bool validatePrevious (Validator *pThis, int iVal) { PreviousValue *pPrevious = (PreviousValue *)pThis->pData; if (iVal < pPrevious->previousValue) return false ; pPrevious->previousValue = iVal; return true ; } bool validate (Validator *p, int iVal) { if (!p) return true ; return p->validate(p, iVal); } bool push (Stack *p, int iVal) { if (!validate(p->pValidator, iVal) || isStackFull(p)) return false ; p->pBuf[p->top++] = iVal; return true ; } bool pop (Stack *p, int *pRet) { if (isStackEmpty(p)) return false ; *pRet = p->pBuf[--p->top]; return true ; }
C语言中的一些设计模式 模板方法模式 在C语言中,资源管理是一件繁琐的事,资源分配与释放成对出现(例如fopen打开文件后在fclose关闭文件,malloc分配内存在free释放掉内存)。而使用资源的具体逻辑代码被夹在管理(分配和释放)资源的代码之间,甚至需要在多处使用资源返回处都需要释放资源。
例如该例子,资源打开释放与逻辑处理相互耦合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int range (const char *pFname) { FILE *fp = fopen(pFname, "r" ); if (NULL == fp) return -1 ; int min = INT_MAX; int max = INT_MIN; char buf[256 ]; while ((fgets(buf, sizeof (buf), fp)) != NULL ){ int value = atoi(buf); min = min > value ? value : min; max = max < value ? value : max; } fclose(fp); return max - min; }
对于这样的程序结构,模板(Template)方法模式非常有效。模板方法将程序中的处理部分作为可以被替代的函数(使用函数指针实现模板方法),将其它处理作为固定部分,使其可以被重复利用。
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 typedef struct FileReaderContext { const char * const pFname; void (* const processor)(struct FileReaderContext *pThis, FILE *fp); } FileReaderContext; typedef struct { FileReaderContext base; int result }MyFileReaderContext; static void calc_range (FileReaderContext *p, FILE *p) { MyFileReaderContext *pCtx = (MyFileReaderContext *)p; pCtx->result = range_processor(fp); } int read_file (FileReaderContext *pCtx) { FILE *fp = fopen(pCtx->pFname, "r" ); if (NULL = fp) return -1 ; pCtx->processor(pCtx, fp); fclose(fp); return 0 ; } int range (const char *pFname) { MyFileReaderContext ctx = {{pFname, calc_range}, 0 }; if (read_file(&ctx.base) != 0 ){ fprintf (stderr , "Cannot open file '%s'.\n" ,pFname); } return ctx.result; }
当需要使用多种资源时,又如何使用模版方法呢?例如:将一个文件中的数据读取至内存,进行排序后在输出至另一个文件的情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 static long file_size (FILE *fp) ; int process_file ( const char *pInputFileName, const char *pOutputFileName, void (*sorter)(void *pBuf)) { FILE *fpInp = fopen(pInputFileName, "rb" ); if (NULL == fpInp) { return FILE_OPEN_ERROR; } long size = file_size(fpInp); void *p = malloc (size); if (NULL == p) return NO_MEMORY_ERROR; fread(p,size,1 ,fpInp); ... }
处理文件打开的模板方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 typedef struct FileAccessorContext { const char * const pFname; const char * const pMode; void (* const processor)(struct FileAccessorContext *pThis, FILE *fp); }FileAccessorContext; bool access_file (FileAccessorContext *pCtx) { FILE *fp = fopen(pCtx->pFname, pCtx->pMode); if (NULL == fp) return false ; pCtx->processor(pCtx,fp); fclose(fp); return ture; }
分配内存的模板方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 typedef struct BufferContext { void *pBuf; size_t size; void (*processor)(struct BufferContext *p); }BufferContext; bool buffer (BufferContext *pThis) { pThis->pBuf = malloc (pThis->size); if (NULL == pThis->pBuf) return false ; pThis->processor(pThis); free (pThis->pBuf); return ture; }
获取文件大小的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 typedef struct { FileAccessorContext base; long size; }SizeGetterContext; static long file_size (const char *pFname) { SizeGetterContext ctx = {{pFname, "rb" , size_reader}, 0 }; if (!access_file(&ctx.base)){ return -1 ; } return ctx.size; } static void size_reader (FileAccessorContext *p, FILE *fp) { SizeGetterContext *pThis = (SizeGetterContext *)p; pThis->size = -1 ; if (fseek(fp, 0 , SEEK_END) == 0 ) pThis->size = ftell(fp); }
内存排序与错误处理。
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 typedef enum { ERR_CAT_OK = 0 , ERR_CAT_FILE, ERR_CAT_MEMORY }IntSorterError; typedef struct { const char * const pFname; int errorCategory; }Context; typedef struct { BufferContext base; Context *pAppCtx; }MyBufferContext; IntSorterError int_sorter (const char *pFname) { Context ctx = {pFname, ERR_CAT_OK}; long size = file_size(pFname); if (size == -1 ){ file_error(&ctx); return ctx.errorCategory; } MyBufferContext bufCtx = {{NULL , size, do_with_buffer}, &ctx}; if (!buffer(&bufCtx.base)){ ctx.errorCategory = ERR_CAT_MEMORY; } return ctx.errorCategory; } static void file_error (Context *pCtx) { fprintf (stderr , "%s:%s\n" , pCtx->pFname, strerror(errno)); pCtx->errorCategory = ERR_CAT_FILE; } typedef struct { FileAccessorCOntext base; MyBufferContext *pBufCtx; }MyFileAccessorContext; static void do_with_buffer (BufferContext *p) { MyBufferContext *pBufCtx = (MyBufferContext *)p; MyFileAccessorContext readFileCtx = {{pBufCtx->pAppCtx->pFname,"rb" , \ reader}, pBufCtx}; if (!access_file(&readFileCtx.base)){ file_error(pBufCtx->pAppCtx); return ; } qsort(p->pBuf, p->size / sizeof (int ), sizeof (int ), comparator); MyFileAccessorContext writeFileCtx = {{pBufCtx->pAppCtx->pFname,"wb" , \ writer},pBufCtx}; if (!access_file(&writeFileCtx.base)){ file_error(pBufCtx->pAppCtx); return ; } } static void reader (FileAccessorContext *p, FILE *fp) { MyFileAccessorContext *pFileCtx = (MyFileAccessorContext *)p; MyBufferContext *pBufCtx = pFileCtx->pBufCtx; if (pBufCtx->base.size != fread(pBufCtx->base.pBuf, 1 , \ pBufCtx->Base.size, fp)){ file_error(pBufCtx->pAppCtx); } } static void writer (FileAccessorContext *p, FILE *fp) { MyFileAccessorContext *pFileCtx = (MyFileAccessorContext *)p; MyBufferContext *pBufCtx = pFileCtx->pBufCtx; if (fwrite(pBufCtx->base.pBuf,1 ,pBufCtx->base.size, fp) != \ pBufCtx->base.size){ file_error(pBufCtx->pAppCtx); } }
如上的处理流程中一共两次打开和关闭文件:首先打开文件计算大小,关闭,然后打开文件读取内容,关闭。为此还可以修改一下,将获取所需内存大小推迟至调用用户自定义函数后处理。内存分配函数指定大小的内存,并将其保存至上下文中返回给用户自定义函数处理。
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 typedef struct BufferContext { void *pBuf; size_t size; bool (*processor)(struct BufferContext *p); }BufferContext; bool buffer (BufferContext *pThis) { assert(pThis); bool ret = pThis->processor(pThis); free (pThis->pBuf); return ret; } void *allocate_buffer (BufferContext *pThis, size_t size) { assert(pThis); assert(pThis->pBuf == NULL ); pThis->pBuf = malloc (size); pThis->size = size; return pThis->pBuf; } typedef struct FileAccessorContext { FILE *fp; const char * const pFname; const char * const pMode; bool (* const processor)(struct FileAccessorContext *pThis) }FileAccessorContext; bool access_file (FileAccessorContext *pThis) { assert(pThis); bool ret = pThis->processor(pThis); if (pThis->fp != NULL ){ if (fclose(pThis->fp) != 0 ) ret = false ; } return ret; } FILE *get_file_pointer (FileAccessorContext *pThis) { assert(pThis); if (pThis->fp == NULL ){ pThis->fp = fopen(pThis->pFname, pThis->pMode); } return pThis->fp; } typedef struct { const char * const pFname; int errorCategory; }Context; IntSorterError int_sorter (const char *pFname) { Context ctx = {pFname, ERROR_CAT_OK}; MyBufferContext bufCtx = {{NULL , 0 , do_with_buffer}, &ctx}; buffer(&bufCtx.base); return ctx.errorCategory; } static bool do_with_buffer (BufferContext *p) { MyBufferContext *pBufCtx = (MyBufferContext *)p; MyFileAccessorContext readFileCtx = \ {{NULL ,pBufCtx->pAppCtx->pFname,"rb" ,reader}, pBufCtx}; if (!access_file(&readFileCtx.base)){ file_error(pBufCtx->pAppCtx); return false ; } qsort(p->pBuf, p->size / sizeof (int ), sizeof (int ), comparator); MyFileAccessorContext writeFileCtx = \ {{NULL ,pBufCtx->pAppCtx->pFname,"wb" ,write}, pBufCtx}; if (!access_file(&writeFileCtx.base)){ file_error(pBufCtx->pAppCtx); return false ; } return ture; } static bool reader (FileAccessorContext *p) { MyFileAccessorContext *pFileCtx = (MyFileAccessorContext *)p; MyBufferContext *pBufCtx = pFileCtx->pBufCtx; long size = file_size(p); if (size == -1 ){ file_error(pBufCtx->pAppCtx); return false ; } if (!allocate_buffer(&pBufCtx->base, size)){ pBufCtx->pAppCtx->errorCategory = ERR_CAT_MEMORY; return false ; } FILE *fp = get_file_pointer(p); if (pBufCtx->base.size != fread(pBufCtx->base.pBuf, 1 , \ pBufCtx->base.size, fp)){ file_error(pBufCtx->pAppCtx); return false ; } return ture; } static bool writer (FileAccessorContext *p) { MyFileAccessorContext *pFileCtx = (MyFileAccessorContext *)p; MyBufferContext *pBufCtx = pFileCtx->pBufCtx; FILE *fp = get_file_pointer(p); if (fwrite(pBufCtx->base.pBuf, 1 , pBufCtx->base.size, fp) != \ pBufCtx->base.size){ file_error(pBufCtx->pAppCtx); return false ; } return ture; } static long file_size (FileAccessorContext *pThis) { long save = file_current_pos(pThis); if (save < 0 ) return -1 ; if (set_file_pos(pThis, 0 , SEEK_END) != 0 ) return -1 ; long size = file_current_pos(pThis); if (set_file_pos(pThis, save, SEEK_SET) != 0 ) return -1 ; return size; } static long file_current_pos (FileAccessorContext *pFileCtx) { assert(pFileCtx); FILE *fp = get_file_pointer(pFileCtx); if (NULL == fp) return -1 ; return ftell(fp); } static int set_file_pos (FileAccessorContext *pFileCtx, long offset, \ int whence) { assert(pFileCtx); FILE *fp = get_file_pointer(pFileCtx); if (NULL == fp) return -1 ; return fseek(fp, offset, whence); }
观察者模式 在模板方法模式例子中,如果指定一个不存在的文件int_sorter(“no_such_file”)时,其内部geit_file_pointer函数内部fopen函数调用失败。导致外部reader函数与do_with_buffer函数也会检测出错误,将错误信息打印出来,导致错误信息被输出了2次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 struct FileAccessorContext ;typedef struct FileErrorObserver { void (* const onError) (struct FileErrorObserver *pThis, \ Struct FileAccessorContext *pFileCtx); }FileErrorObserver; extern FileErrorObserver default_file_error_observer;typedef struct FileAccessorContext { FILE *fp; const char *pFname; const char *pMode; bool (* const processor)(struct FileAccessorContext *pThis); FileErrorObserver *pFileErrorObserver; }FileAccessorContext;
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 FileErrorObserver default_file_error_observer = { &default_file_error_handler }; bool access_file (FileAccessorContext *pThis) { assert(pThis); if (pThis->pFileErrorObserver == NULL ) pThis->pFileErrorObserver = &default_file_error_observer; bool ret = pThis->processor(pThis); if (pThis->fp != NULL ) { if (fclose(pThis->fp) != 0 ) { pThis->pFileErrorObserver->onError( \ pThis->pFileErrorObserver, pThis); ret = false ; } } return ret; } FILE *get_file_pointer (FileAccessorContext *pThis) { assert(pThis); if (pThis->fp == NULL ) { pThis->fp = fopen(pThis->pFname, pThis->pMode); if (pThis->fp == NULL ) pThis->pFileErrorObserver->onError( \ pThis->pFileErrorObserver, pThis); } return pThis->fp; } static void default_file_error_handler (FileErrorObserver *pThis \ FileAccessorContext *pFileCtx) { fprintf (stderr , "File access error '%s'(mode: %s): %s\n" , \ pFileCtx->pFname, pFileCtx->pMode, strerror(errno)); }
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 long file_size (FileAccessorContext *pFileCtx) { long save = file_current_pos(pFileCtx); if (save < 0 ) return -1 ; if (set_file_pos(pFileCtx, 0 , SEEK_END) != 0 ) return -1 ; long size = file_current_pos(pFileCtx); set_file_pos(pFileCtx, save, SEEK_SET); return size; } long file_current_pos (FileAccessorContext *pThis) { assert(pThis); FILE *fp = get_file_pointer(pThis); if (fp == NULL ) return -1 ; long ret = ftell(fp); if (ret < 0 ) pThis->pFileErrorObserver->onError( \ pThis->pFileErrorObserver, pThis); return ret; } int set_file_pos (FileAccessorContext *pThis, long offset, int whence) { assert(pThis); FILE *fp = get_file_pointer(pThis); if (fp == NULL ) return -1 ; int ret = fseek(fp, offset, whence); if (ret != 0 ) pThis->pFileErrorObserver->onError( \ pThis->pFileErrorObserver, pThis); return ret; } bool read_file (FileAccessorContext *pThis, BufferContext *pBufCtx) { FILE *fp = get_file_pointer(pThis); if (fp == NULL ) return false ; if (pBufCtx->size != fread(pBufCtx->pBuf, 1 , pBufCtx->size, fp)) { pThis->pFileErrorObserver->onError(pThis->pFileErrorObserver, \ pThis); return false ; } return true ; } bool write_file (FileAccessorContext *pThis, BufferContext *pBufCtx) { FILE *fp = get_file_pointer(pThis); if (fp == NULL ) return false ; if (pBufCtx->size != fwrite(pBufCtx->pBuf, 1 , pBufCtx->size, fp)) { pThis->pFileErrorObserver->onError(pThis->pFileErrorObserver, \ pThis); return false ; } return true ; }
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 static bool reader (FileAccessorContext *pFileCtx) ;static bool do_with_buffer (BufferContext *pBufCtx) ;static bool writer (FileAccessorContext *pFileCtx) ;static int comparator (const void *p1, const void *p2) ;static void file_error (FileErrorObserver *pThis, \ FileAccessorContext *pFileCtx) ;typedef struct { BufferContext base; Context *pAppCtx; } MyBufferContext; typedef struct { FileAccessorContext base; MyBufferContext *pBufCtx; } MyFileAccessorContext; typedef struct { FileAccessorContext base; long size; } SizeGetterContext; static FileErrorObserver file_error_observer = { file_error }; IntSorterError int_sorter (const char *pFname) { Context ctx = {pFname, ERR_CAT_OK}; MyBufferContext bufCtx = {{NULL , 0 , do_with_buffer}, &ctx}; buffer(&bufCtx.base); return ctx.errorCategory; } static bool do_with_buffer (BufferContext *p) { MyBufferContext *pBufCtx = (MyBufferContext *)p; MyFileAccessorContext readFileCtx = { {NULL , pBufCtx->pAppCtx->pFname, "rb" , reader, \ &file_error_observer}, pBufCtx }; if (! access_file(&readFileCtx.base)) return false ; qsort(p->pBuf, p->size / sizeof (int ), sizeof (int ), comparator); MyFileAccessorContext writeFileCtx = { {NULL , pBufCtx->pAppCtx->pFname, "wb" , writer, \ &file_error_observer},pBufCtx}; return access_file(&writeFileCtx.base); } static bool reader (FileAccessorContext *p) { MyFileAccessorContext *pFileCtx = (MyFileAccessorContext *)p; long size = file_size(p); if (size == -1 ) return false ; if (! allocate_buffer(&pFileCtx->pBufCtx->base, size)) { pFileCtx->pBufCtx->pAppCtx->errorCategory = ERR_CAT_MEMORY; return false ; } return read_file(p, &pFileCtx->pBufCtx->base); } static bool writer (FileAccessorContext *p) { MyFileAccessorContext *pFileCtx = (MyFileAccessorContext *)p; return write_file(p, &pFileCtx->pBufCtx->base); } static int comparator (const void *p1, const void *p2) { int i1 = *(const int *)p1; int i2 = *(const int *)p2; if (i1 < i2) return -1 ; if (i1 > i2) return 1 ; return 0 ; } static void file_error (FileErrorObserver *pThis, \ FileAccessorContext *pFileCtx) { default_file_error_observer.onError(pThis, pFileCtx); MyFileAccessorContext *pMyFileCtx = (MyFileAccessorContext *)pFileCtx; pMyFileCtx->pBufCtx->pAppCtx->errorCategory = ERR_CAT_FILE; }
观察者模式基本上会通过使用回调来切断监控方与被监控对象之间的依赖关系。
动态增加观察者的观察模式 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 typedef struct ArrayList { const int capacity; void ** const pBuf; size_t index; struct ArrayList *(* const add )(struct ArrayList *pThis , void *pData ); void *(* const remove)(struct ArrayList *pThis, void *pData); void *(* const get)(struct ArrayList *pThis, int index); size_t (* const size)(struct ArrayList *pThis); } ArrayList; ArrayList *add_to_array_list (ArrayList *pThis, void *pData) ; void *remove_from_array_list (ArrayList *pThis, void *pData) ;void *get_from_array_list (ArrayList *pThis, int index) ;size_t array_list_size (ArrayList *pThis) ;#define new_array_list(array) \ {sizeof(array) / sizeof(void *), array, \ 0, add_to_array_list, remove_from_array_list, \ get_from_array_list, array_list_size} ArrayList *add_to_array_list (ArrayList *pThis, void *pData) { assert(pThis->capacity > pThis->index); pThis->pBuf[pThis->index++] = pData; return pThis; } void *remove_from_array_list (ArrayList *pThis, void *pData) { int i; for (i = 0 ; i < pThis->index; ++i) { if (pThis->pBuf[i] == pData) { memmove(pThis->pBuf + i, pThis->pBuf + i + 1 , \ (pThis->index - i - 1 ) * sizeof (void *)); --pThis->index; return pData; } } return NULL ; } void *get_from_array_list (ArrayList *pThis, int index) { assert(0 <= index && pThis->index > index); return pThis->pBuf[index]; } size_t array_list_size (ArrayList *pThis) { return pThis->index; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 struct FileAccessorContext ;typedef struct FileErrorObserver { void (* const onError)(struct FileErrorObserver *pThis, \ struct FileAccessorContext *pFileCtx); } FileErrorObserver; extern FileErrorObserver default_file_error_observer;typedef struct FileAccessorContext { FILE *fp; const char *pFname; const char *pMode; ArrayList observer_table; bool (* const processor)(struct FileAccessorContext *pThis); } FileAccessorContext;
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 bool access_file (FileAccessorContext *pThis) { assert(pThis); bool ret = pThis->processor(pThis); if (pThis->fp != NULL ) { if (fclose(pThis->fp) != 0 ) { fire_error(pThis); ret = false ; } } return ret; } static void fire_error (FileAccessorContext *pThis) { ArrayList *pTbl = &pThis->observer_table; int i; for (i = 0 ; i < pTbl->index; ++i) { FileErrorObserver *pObserver = pTbl->get(pTbl, i); pObserver->onError(pObserver, pThis); } } void add_file_error_observer (FileAccessorContext *pThis, \ FileErrorObserver *pErrorObserver) { ArrayList *pTable = &pThis->observer_table; pTable->add(pTable, pErrorObserver); } void remove_file_error_observer (FileAccessorContext *pThis, \ FileErrorObserver *pErrorObserver) { ArrayList *pTable = &pThis->observer_table; pTable->remove(pTable, pErrorObserver); }
责任链模式 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 #ifndef _STACK_H_ #define _STACK_H_ #include <stddef.h> #ifdef __cplusplus extern "C" {#endif typedef struct Validator { bool (* const validate)(struct Validator *pThis, int val); } Validator; typedef struct { Validator base; const int min; const int max; } RangeValidator; typedef struct { Validator base; int previousValue; } PreviousValueValidator; typedef struct ChainedValidator { Validator base; Validator *pWrapped; Validator *pNext; } ChainedValidator; typedef struct { int top; const size_t size; int * const pBuf; Validator * const pValidator; } Stack; bool validateRange (Validator *pThis, int val) ;bool validatePrevious (Validator *pThis, int val) ;bool validateChain (Validator *pThis, int val) ;#define newRangeValidator(min, max) \ {{validateRange}, (min), (max)} #define newPreviousValueValidator \ {{validatePrevious}, 0} #define newChainedValidator(wrapped, next) \ {{validateChain}, (wrapped), (next)} bool push (Stack *p, int val) ;bool pop (Stack *p, int *pRet) ;#define newStack(buf) { \ 0, sizeof(buf) / sizeof(int), (buf), \ NULL \ } #define newStackWithValidator(buf, pValidator) { \ 0, sizeof(buf) / sizeof(int), (buf), \ pValidator \ } #ifdef __cplusplus } #endif #endif
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 #include <stdbool.h> #include "stack.h" static bool isStackFull (const Stack *p) { return p->top == p->size; } static bool isStackEmpty (const Stack *p) { return p->top == 0 ; } bool validateRange (Validator *p, int val) { RangeValidator *pThis = (RangeValidator *)p; return pThis->min <= val && val <= pThis->max; } bool validatePrevious (Validator *p, int val) { PreviousValueValidator *pThis = (PreviousValueValidator *)p; if (val < pThis->previousValue) return false ; pThis->previousValue = val; return true ; } bool validate (Validator *p, int val) { if (! p) return true ; return p->validate(p, val); } bool push (Stack *p, int val) { if (! validate(p->pValidator, val) || isStackFull(p)) return false ; p->pBuf[p->top++] = val; return true ; } bool pop (Stack *p, int *pRet) { if (isStackEmpty(p)) return false ; *pRet = p->pBuf[--p->top]; return true ; } bool validateChain (Validator *p, int val) { ChainedValidator *pThis = (ChainedValidator *)p; p = pThis->pWrapped; if (! p->validate(p, val)) return false ; p = pThis->pNext; return !p || p->validate(p, val); }
访问者模式 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 struct ValidatorVisitor ;typedef struct Validator { bool (* const validate)(struct Validator *pThis, int val); void (* const accept)(struct Validator *pThis, \ struct ValidatorVisitor *pVisitor); } Validator; typedef struct { Validator base; const int min; const int max; } RangeValidator; typedef struct { Validator base; int previousValue; } PreviousValueValidator; typedef struct ValidatorVisitor { void (* const visitRange)(struct ValidatorVisitor *pThis, \ RangeValidator *p); void (* const visitPreviousValue)(struct ValidatorVisitor *pThis, \ PreviousValueValidator *p); } ValidatorVisitor; void acceptRange (Validator *pThis, ValidatorVisitor *pVisitor) ;void acceptPrevious (Validator *pThis, ValidatorVisitor *pVisitor) ;bool validateRange (Validator *pThis, int val) ;bool validatePrevious (Validator *pThis, int val) ;#define newRangeValidator(min, max) \ {{validateRange, acceptRange}, (min), (max)} #define newPreviousValueValidator \ {{validatePrevious, acceptPrevious}, 0} ```` ```c bool validateRange (Validator *p, int val) { RangeValidator *pThis = (RangeValidator *)p; return pThis->min <= val && val <= pThis->max; } bool validatePrevious (Validator *p, int val) { PreviousValueValidator *pThis = (PreviousValueValidator *)p; if (val < pThis->previousValue) return false ; pThis->previousValue = val; return true ; } void acceptRange (Validator *p, ValidatorVisitor *pVisitor) { pVisitor->visitRange(pVisitor, (RangeValidator *)p); } void acceptPrevious (Validator *p, ValidatorVisitor *pVisitor) { pVisitor->visitPreviousValue(pVisitor, (PreviousValueValidator *)p); }
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 static void rangeView (ValidatorVisitor *pThis, RangeValidator *p) ;static void previousValueView (ValidatorVisitor *pThis, \ PreviousValueValidator *p) ;typedef struct ViewVisitor { ValidatorVisitor base; char *pBuf; size_t size; } ViewVisitor; void printValidator (Validator *p, char *pBuf, size_t size) { ViewVisitor visitor = {{rangeView, previousValueView}, pBuf, size}; p->accept(p, &visitor.base); } static void rangeView (ValidatorVisitor *pThis, RangeValidator *p) { ViewVisitor *pVisitor = (ViewVisitor* )pThis; snprintf (pVisitor->pBuf, pVisitor->size, \ "Range(%d-%d)" , p->min, p->max); } static void previousValueView (ValidatorVisitor *pThis, \ PreviousValueValidator *p) { ViewVisitor *pVisitor = (ViewVisitor* )pThis; snprintf (pVisitor->pBuf, pVisitor->size, "Previous" ); }