【 C语言 】 C语言设计模式

打印 上一主题 下一主题

主题 553|帖子 553|积分 1659

一 、C语言和设计模式(继续、封装、多态)
C++有三个最紧张的特点,即继续、封装、多态。我发现其实C语言也是可以面向对象的,也是可以应用设计模式的,关键就在于怎样实现面向对象语言的三个紧张属性。
(1)继续性
[cpp] view plaincopy

  • typedef struct _parent
  • {
    1. int data_parent;  
    复制代码

  • }Parent;

  • typedef struct _Child
  • {
    1. struct _parent parent;  
    复制代码
    1. int data_child;  
    复制代码

  • }Child;
    在设计C语言继续性的时候,我们必要做的就是把基础数据放在继续的布局的首位置即可。这样,不管是数据的访问、数据的强转、数据的访问都不会有什么题目。
(2)封装性
[cpp] view plaincopy

  • struct _Data;

  • typedef void (process)(struct _Data pData);

  • typedef struct _Data
  • {
    1. int value;  
    复制代码
    1. process pProcess;  
    复制代码

  • }Data;
    封装性的意义在于,函数和数据是绑在一起的,数据和数据是绑在一起的。这样,我们就可以通过简单的一个布局指针访问到全部的数据,遍历全部的函数。封装性,这是类拥有的属性,当然也是数据布局体拥有的属性。
(3)多态
[cpp] view plaincopy

  • typedef struct _Play
  • {
    1. void* pData;  
    复制代码
    1. void (*start_play)(struct _Play* pPlay);  
    复制代码
  • }Play;
    多态,就是说用同一的接口代码处理惩罚差别的数据。好比说,这里的Play布局就是一个通用的数据布局,我们也不清楚pData是什么数据,start_play是什么处理惩罚函数?但是,我们处理惩罚的时候只要调用pPlay->start_play(pPlay)就可以了。剩下来的事变我们不必要管,因为差别的接口会有差别的函数行止置惩罚,我们只要学会调用就可以了。
二、C语言和设计模式(访问者模式)
不知不觉当中,我们就到了最后一种设计模式,即访问者模式。访问者模式,听上去复杂一些。但是,这种模式用简单的一句话说,就是差别的人对差别的事物有差别的感觉。好比说吧,豆腐可以做成麻辣豆腐,也可以做成臭豆腐。可是,差别的地方的人未必都喜欢这两种豆腐。四川的朋友大概更喜欢辣豆腐,江浙的人就大概对臭豆腐更喜欢一些。那么,这种情况应该怎么用设计模式表达呢?
[cpp] view plaincopy

  • typedef struct _Tofu
  • {
    1. int type;  
    复制代码
    1. void (*eat) (struct _Visitor* pVisitor, struct _Tofu* pTofu);  
    复制代码
  • }Tofu;

  • typedef struct _Visitor
  • {
    1. int region;  
    复制代码
    1. void (*process)(struct _Tofu* pTofu, struct _Visitor* pVisitor);  
    复制代码
  • }Visitor;
    就是这样一个豆腐,eat的时候就要做差别的判断了。
    [cpp] view plaincopy
  • void eat(struct _Visitor* pVisitor, struct _Tofu* pTofu)
  • {
    1. assert(NULL != pVisitor && NULL != pTofu);  
    复制代码

    1. pVisitor->process(pTofu, pVisitor);  
    复制代码
  • }
    既然eat的操作最后还是靠差别的visitor来处理惩罚了,那么下面就该界说process函数了。
    [cpp] view plaincopy
  • void process(struct _Tofu* pTofu, struct _Visitor* pVisitor)
  • {
    1. assert(NULL != pTofu && NULL != pVisitor);  
    复制代码

    1. if(pTofu->type == SPICY_FOOD && pVisitor->region == WEST ||  
    复制代码
    1.      pTofu->type == STRONG_SMELL_FOOD && pVisitor->region == EAST)  
    复制代码
    1. {  
    复制代码
    1.      printf("I like this food!\n");  
    复制代码
    1.      return;  
    复制代码
    1. }  
    复制代码

    1. printf("I hate this food!\n");     
    复制代码
  • }
三、C语言和设计模式(状态模式)
状态模式是协议交互中使用得比较多的模式。好比说,在差别的协议中,都会存在启动、保持、中止等根本状态。那么怎么机动地转变这些状态就是我们必要思量的事变。假设现在有一个state,
[cpp] view plaincopy

  • typedef struct _State
  • {
    1. void (*process)();  
    复制代码
    1. struct _State* (*change_state)();  
    复制代码

  • }State;
    说明一下,这里界说了两个变量,分别process函数和change_state函数。其中proces函数就是平凡的数据操作,
    [cpp] view plaincopy
  • void normal_process()
  • {
    1. printf("normal process!\n");  
    复制代码
  • }
    change_state函数本质上就是确定下一个状态是什么。
    [cpp] view plaincopy
  • struct _State* change_state()
  • {
    1. State* pNextState = NULL;  
    复制代码

    1. pNextState = (struct _State*)malloc(sizeof(struct _State));  
    复制代码
    1. assert(NULL != pNextState);  
    复制代码

    1. pNextState ->process = next_process;  
    复制代码
    1. pNextState ->change_state = next_change_state;  
    复制代码
    1. return pNextState;  
    复制代码
  • }
    以是,在context中,应该有一个state变量,还应该有一个state变换函数。
    [cpp] view plaincopy
  • typedef struct _Context
  • {
    1. State* pState;  
    复制代码
    1. void (*change)(struct _Context* pContext);  
    复制代码

  • }Context;

  • void context_change(struct _Context* pContext)
  • {
    1. State* pPre;  
    复制代码
    1. assert(NULL != pContext);  
    复制代码

    1. pPre = pContext->pState;  
    复制代码
    1. pContext->pState = pPre->changeState();  
    复制代码
    1. free(pPre);  
    复制代码
    1. return;  
    2.    
    复制代码
  • }
四、 C语言和设计模式(下令模式)
下令模式的目标重要是为了把下令者和实验者分开。老规矩,举个范例吧。假设李老板是一家公司的头儿,他现在让他的秘书王小姐去送一封信。王小姐当然不会自己亲身把信送到目标地,她会把信交给邮局来完成整个投递的全过程。现在,我们就对投递者、下令、发令者分别作出界说。
  1. 首先定义post的相关数据。
复制代码
[cpp] view plaincopy

  • typedef struct _Post
  • {
    1. void (*do)(struct _Post* pPost);     
    复制代码
  • }Post;
    Post完成了实际的投递工作,那么下令呢?
    [cpp] view plaincopy
  • typedef struct _Command
  • {
    1. void* pData;  
    复制代码
    1. void (*exe)(struct _Command* pCommand);  
    复制代码

  • }Command;

  • void post_exe(struct _Command* pCommand)
  • {
    1. assert(NULL != pCommand);  
    复制代码

    1. (Post*)(pCommand->pData)->do((Post*)(pCommand->pData));  
    复制代码
    1. return;  
    复制代码
  • }
    我们看到了Post、Command的操作,那么剩下的就是boss的界说了。
    [cpp] view plaincopy
  • typedef struct _Boss
  • {
    1. Command* pCommand;  
    复制代码
    1. void (*call)(struct _Boss* pBoss);  
    复制代码
  • }Boss;

  • void boss_call(struct _Boss* pBoss)
  • {
    1. assert(NULL != pBoss);  
    复制代码

    1. pBoss->pCommand->exe(pBoss->pCommand);  
    复制代码
    1. return;  
    复制代码
  • }
五、C语言和设计模式(解释器模式)
解释器模式虽然听上去有些费解,但是如果用示例说明一下就不难理解了。我们知道在C语言中,关于变量的界说是这样的:一个不以数字开始的由字母、数字和下划线构成的字符串。这种形式的表达式可以用状态主动机办理,当然也可以用解释器的方式办理。
[cpp] view plaincopy

  • typedef struct _Interpret
  • {
    1. int type;  
    复制代码
    1. void* (*process)(void* pData, int* type, int* result);  
    复制代码

  • }Interpret;
    上面的数据布局比较简单,但是很能说明题目。就拿变量来说吧,这里就可以界说成字母的解释器、数字解释器、下划线解释器三种形式。以是,我们可以进一步界说一下process的相干函数。
[cpp] view plaincopy

  • #define DIGITAL_TYPE 1
  • #define LETTER_TYPE 2
  • #define BOTTOM_LINE 3

  • void* digital_process(void* pData, int* type, int* result)
  • {
    1. UINT8* str;  
    复制代码
    1. assert(NULL != pData && NULL != type && NULL != result);  
    复制代码

    1. str = (UNT8*)pData;  
    复制代码
    1. while (*str >= '0' && *str <= '9')  
    复制代码
    1. {  
    复制代码
    1.     str ++;  
    复制代码
    1. }  
    复制代码

    1. if(*str == '\0')  
    复制代码
    1. {  
    复制代码
    1.     *result = TRUE;  
    复制代码
    1.     return NULL;  
    复制代码
    1. }  
    2.    
    复制代码

    1. if(*str == '_')  
    复制代码
    1. {  
    复制代码
    1.     *result = TRUE;  
    复制代码
    1.     *type = BOTTOM_TYPE;  
    复制代码
    1.     return str;  
    复制代码
    1. }  
    复制代码

    1. if(*str >= 'a' && *str <= 'z' || *str >= 'A' && *str <= 'Z')  
    复制代码
    1. {  
    复制代码
    1.     *result = TRUE;  
    复制代码
    1.     *type = LETTER_TYPE;  
    复制代码
    1.     return str;  
    复制代码
    1. }  
    复制代码

    1. *result = FALSE;  
    复制代码
    1. return NULL;              
    复制代码
  • }

  • void* letter_process(void* pData, int* type, int* result)
  • {
    1. UINT8* str;  
    复制代码
    1. assert(NULL != pData && NULL != type && NULL != result);  
    复制代码

    1. str = (UNT8*)pData;  
    复制代码
    1. while (*str >= 'a' && *str <= 'z' || *str >= 'A' && *str <= 'Z')  
    复制代码
    1. {  
    复制代码
    1.     str ++;  
    复制代码
    1. }  
    复制代码

    1. if(*str == '\0')  
    复制代码
    1. {  
    复制代码
    1.     *result = TRUE;  
    复制代码
    1.     return NULL;  
    复制代码
    1. }  
    2.    
    复制代码

    1. if(*str == '_')  
    复制代码
    1. {  
    复制代码
    1.     *result = TRUE;  
    复制代码
    1.     *type = BOTTOM_TYPE;  
    复制代码
    1.     return str;  
    复制代码
    1. }  
    复制代码

    1. if(*str >= '0' && *str <= '9')  
    复制代码
    1. {  
    复制代码
    1.     *result = TRUE;  
    复制代码
    1.     *type = DIGITAL_TYPE;  
    复制代码
    1.     return str;  
    复制代码
    1. }  
    复制代码

    1. *result = FALSE;  
    复制代码
    1. return NULL;              
    复制代码
  • }

  • void* bottom_process(void* pData, int* type, int* result)
  • {
    1. UINT8* str;  
    复制代码
    1. assert(NULL != pData && NULL != type && NULL != result);  
    复制代码

    1. str = (UNT8*)pData;  
    复制代码
    1. while ('_' == *str )  
    复制代码
    1. {  
    复制代码
    1.     str ++;  
    复制代码
    1. }  
    复制代码

    1. if(*str == '\0')  
    复制代码
    1. {  
    复制代码
    1.     *result = TRUE;  
    复制代码
    1.     return NULL;  
    复制代码
    1. }  
    2.    
    复制代码

    1. if(*str >= 'a' && *str <= 'z' || *str >= 'A' && *str <= 'Z')  
    复制代码
    1. {  
    复制代码
    1.     *result = TRUE;  
    复制代码
    1.     *type = LETTER_TYPE;  
    复制代码
    1.     return str;  
    复制代码
    1. }  
    复制代码

    1. if(*str >= '0' && *str <= '9')  
    复制代码
    1.    {  
    复制代码
    1.        *result = TRUE;  
    复制代码
    1.        *type = DIGITAL_TYPE;  
    复制代码
    1.        return str;  
    复制代码
    1.    }  
    复制代码

    1.    *result = FALSE;  
    复制代码
    1.    return NULL;              
    复制代码
  • }
六、C语言和设计模式(备忘录模式)
备忘录模式的起源来自于取消的根本操作。有过word软件操作履历的朋友,应该根本上都使用过取消的功能。举个例子,假设你不鉴戒删除了好几个段落的文字,这时候你应该怎么办呢?其实要做的很简单,单击一些【取消】就可以全部搞定了。取消按钮给我们提供了一次反悔的机会。
  1. 既然是撤销,那么我们在进行某种动作的时候,就应该创建一个相应的撤销操作?这个撤销操作的相关定义可以是这样的。
复制代码
[cpp] view plaincopy

  • typedef struct _Action
  • {
    1. int type;  
    复制代码
    1. struct _Action* next;  
    复制代码

    1. void* pData;  
    复制代码
    1. void (*process)(void* pData);  
    复制代码

  • }Action;
    数据布局中界说了两个部分:取消的数据、恢复的操作。那么这个取消函数应该有一个创建的函数,还有一个恢复的函数。以是,作为取消动作的管理者应该包罗,
    [cpp] view plaincopy
  • typedef struct _Organizer
  • {
    1. int number;  
    复制代码
    1. Action* pActionHead;  
    复制代码

    1. Action* (*create)();  
    复制代码
    1. void (*restore)(struct _Organizer* pOrganizer);   
    复制代码
  • }Organizer;
    既然数据在创建和修改的过程中都会有相应的恢复操作,那么要是真正恢复原来的数据也就变得非常简单了。
    [cpp] view plaincopy
  • void restore(struct _Organizer* pOrganizer)
  • {
    1. Action* pHead;  
    复制代码
    1. assert(NULL != pOrganizer);  
    复制代码

    1. pHead = pOrganizer->pActionHead;  
    复制代码
    1. pHead->process(pHead->pData);  
    复制代码
    1. pOrganizer->pActionHead = pHead->next;  
    复制代码
    1. pOrganizer->number --;  
    复制代码
    1. free(pHead);  
    复制代码
    1. return;  
    复制代码
  • }
七、C语言和设计模式(观察者模式)
观察者模式大概是我们在软件开发中使用得比较多的一种设计模式。为什么这么说?各人可以听我一一到来。我们知道,在windows的软件中,全部的界都是由窗口构成的。对话框是窗口,菜单是窗口,工具栏也是窗口。那么这些窗口,在许多情况下要对一些共有的信息举行处理惩罚。好比说,窗口的放大,窗口的减小等等。面临这一情况,观察者模式就是不错的一个选择。
起首,我们可以对这些共有的object举行提炼。
[cpp] view plaincopy

  • typedef struct _Object
  • {
    1. observer* pObserverList[MAX_BINDING_NUMBER];  
    复制代码
    1. int number;  
    复制代码

    1. void (*notify)(struct _Object* pObject);  
    复制代码
    1. void (*add_observer)(observer* pObserver);  
    复制代码
    1. void (*del_observer)(observer* pObserver);  
    复制代码

  • }Object;
    其实,我们必要界说的就是观察者自己了。就像我们前面说的一样,观察者可以是菜单、工具栏大概是子窗口等等。
    [cpp] view plaincopy
  • typedef struct _Observer
  • {
    1. Object* pObject;  
    复制代码

    1. void (*update)(struct _Observer* pObserver);  
    复制代码
  • }Observer;
    紧接着,我们要做的就是在Observer创建的时候,把observer自身绑定到Object上面。
    [cpp] view plaincopy
  • void bind_observer_to_object(Observer* pObserver, Object* pObject)
  • {
    1. assert(NULL != pObserver && NULL != pObject);  
    复制代码

    1. pObserver->pObject = pObject;  
    复制代码
    1. pObject->add_observer(pObserver);  
    复制代码
  • }

  • void unbind_observer_from_object(Observer* pObserver, Object* pObject)
  • {
    1. assert(NULL != pObserver && NULL != pObject);  
    复制代码

    1. pObject->del_observer(observer* pObserver);  
    复制代码
    1. memset(pObserver, 0, sizeof(Observer));  
    复制代码
  • }
    既然Observer在创建的时候就把自己绑定在某一个具体的Object上面,那么Object发生改变的时候,统一更新操作就是一件很轻易的事变了。
    [cpp] view plaincopy
  • void notify(struct _Object* pObject)
  • {
    1. Obserer* pObserver;  
    复制代码
    1. int index;  
    复制代码

    1. assert(NULL != pObject);  
    复制代码
    1. for(index = 0; index < pObject->number; index++)  
    复制代码
    1. {  
    复制代码
    1.      pObserver = pObjecet->pObserverList[index];  
    复制代码
    1.     pObserver->update(pObserver);  
    复制代码
    1. }  
    复制代码
  • }
八、C语言和设计模式(桥接模式)
在以往的软件开发过程中,我们总是强调模块之间要低耦合,模块自己要高内聚。那么,可以通过哪些设计模式来实现呢?桥接模式就是不错的一个选择。我们知道,在现实的软件开发过程当中,用户的要求是多种多样的。好比说,有这么一个饺子店吧。假设饺子店原来只卖肉馅的饺子,可是后来一些吃素的顾客说能不能做一些素的饺子。听到这些要求的老板天然不敢怠慢,以是也开始卖素饺子。之后,又有顾客提出,现在的肉馅饺子只有猪肉的,能不能做点牛肉、羊肉馅的饺子?一些只吃素的顾客也故意见了,他们发起能不能增长一些素馅饺子的品种,什么白菜馅的、韭菜馅的,都可以做一点。由此看来,顾客的要求是一层一层递增的。关键是我们怎样把顾客的要求和我们的实现的接口举行有效地分离呢?
其实我们可以这么做,通常的产品还是按照共同的属性举行归类。
[cpp] view plaincopy

  • typedef struct _MeatDumpling
  • {
    1. void (*make)();  
    复制代码
  • }MeatDumpling;

  • typedef struct _NormalDumpling
  • {
    1. void (*make)();  
    复制代码
  • }NormalDumpling;
    上面只是对饺子举行归类。第一类是对肉馅饺子的归类,第二类是对素馅饺子的归类,这些地方都没有什么特殊之处。那么,关键是我们怎么把它和顾客的要求接洽在一起呢?
    [cpp] view plaincopy
  • typedef struct _DumplingReuqest
  • {
    1. int type;  
    复制代码
    1. void* pDumpling;     
    复制代码
  • }DumplingRequest;
    这里界说了一个饺子买卖的接口。它的特殊支持就在于两个地方,第一是我们界说了饺子的类型type,这个type是可以任意扩充的;第二就是这里的pDumpling是一个void*指针,只有把它和具体的dumpling绑定才会衍生出具体的寄义。
    [cpp] view plaincopy
  • void buy_dumpling(DumplingReuqest* pDumplingRequest)
  • {
    1. assert(NULL != pDumplingRequest);  
    复制代码

    1. if(MEAT_TYPE == pDumplingRequest->type)  
    复制代码
    1.      return (MeatDumpling*)(pDumplingRequest->pDumpling)->make();  
    复制代码
    1. else  
    复制代码
    1.      return (NormalDumpling*)(pDumplingRequest->pDumpling)->make();  
    复制代码
  • }
九、C语言和设计模式(建造者模式)
如果说前面的工厂模式是对接口举行抽象化处理惩罚,那么建造者模式更像是对流程自己的一种抽象化处理惩罚。这话怎么理解呢?各人可以听我慢慢到来。以前买电脑的时候,各人都喜欢自己组装呆板。一方面可以满意自己的个性化需求,另外一方面也可以在代价上得到许多实惠。但是电脑是由许多部分构成的,每个厂家都只负责其中的一部分,而且相同的组件也有许多的品牌可以从中选择。这对于我们消费者来说当然非常有利,那么应该怎么设计呢?
[cpp] view plaincopy

  • typedef struct _AssemblePersonalComputer
  • {
    1. void (*assemble_cpu)();  
    复制代码
    1. void (*assemble_memory)();  
    复制代码
    1. void (*assemble_harddisk)();  
    复制代码

  • }AssemblePersonalComputer;
    对于一个希望配置intel cpu,samsung 内存、日立硬盘的朋友。他可以这么设计,
    [cpp] view plaincopy
  • void assemble_intel_cpu()
  • {
    1. printf("intel cpu!\n");  
    复制代码
  • }

  • void assemble_samsung_memory()
  • {
    1. printf("samsung memory!\n");  
    复制代码
  • }

  • void assemble_hitachi_harddisk()
  • {
    1. printf("hitachi harddisk!\n");  
    复制代码
  • }
    而对于一个希望配置AMD cpu, kingston内存、西部数据硬盘的朋友。他又该怎么做呢?
    [cpp] view plaincopy
  • void assemble_amd_cpu()
  • {
    1. printf("amd cpu!\n");  
    复制代码
  • }

  • void assemble_kingston_memory()
  • {
    1. printf("kingston memory!\n");  
    复制代码
  • }

  • void assmeble_western_digital_harddisk()
  • {
    1. printf("western digital harddisk!\n");  
    复制代码
  • }
十、 C语言和设计模式(中介者模式)
中介者模式,听上去有一点生疏。但是,只要我给朋友们打个比方就明白了。早先自由爱情没有现在那么普遍的时候,男女之间的相识还是必要通过牙婆之间才能相互熟悉。男孩对女方有什么要求,可以通过牙婆向女方提出来;当然,女方有什么要求也可以通过牙婆向男方提出来。以是,中介者模式在我看来,就是牙婆模式。
[cpp] view plaincopy

  • typedef struct _Mediator
  • {
    1. People* man;  
    复制代码
    1. People* woman;   
    复制代码
  • }Mediator;
    上面的数据布局是给牙婆的,那么当然还有一个数据布局是给男方、女方的。
    [cpp] view plaincopy
  • typedef struct _People
  • {
    1. Mediator* pMediator;  
    复制代码

    1. void (*request)(struct _People* pPeople);  
    复制代码
    1. void (*process)(struct _Peoplle* pPeople);  
    复制代码
  • }People;
    以是,这里我们看到的如果是男方的要求,那么这个要求应该女方行止置惩罚啊,怎么处理惩罚呢?
    [cpp] view plaincopy
  • void man_request(struct _People* pPeople)
  • {
    1. assert(NULL != pPeople);  
    复制代码

    1. pPeople->pMediator->woman->process(pPeople->pMediator->woman);     
    复制代码
  • }
    上面做的是男方向女方提出的要求,以是女方也可以向男方提要求了。毕竟男女平等嘛。
    [cpp] view plaincopy
  • void woman_request(struct _People* pPeople)
  • {
    1. assert(NULL != pPeople);  
    复制代码

    1. pPeople->pMediator->man->process(pPeople->pMediator->man);  
    复制代码
  • }
十一、C语言和设计模式(策略模式)
策略模式就是用统一的方法接口分别对差别类型的数据举行访问。好比说,现在我们想用pc看一部影戏,此时应该怎么做呢?看影戏嘛,当然必要各种播放影戏的方法。rmvb要rmvb格式的方法,avi要avi的方法,mpeg要mpeg的方法。可是毕竟上,我们完全可以不去管是什么文件格式。因为播放器对全部的操作举行了抽象,差别的文件会主动调用相应的访问方法。
[cpp] view plaincopy

  • typedef struct _MoviePlay
  • {
    1. struct _CommMoviePlay* pCommMoviePlay;  
    复制代码

  • }MoviePlay;

  • typedef struct _CommMoviePlay
  • {
    1. HANDLE hFile;  
    复制代码
    1. void (*play)(HANDLE hFile);  
    复制代码

  • }CommMoviePlay;
    这个时候呢,对于用户来说,统一的文件接口就是MoviePlay。接下来的一个工作,就是编写一个统一的访问接口。
    [cpp] view plaincopy
  • void play_movie_file(struct MoviePlay* pMoviePlay)
  • {
    1. CommMoviePlay* pCommMoviePlay;  
    复制代码
    1. assert(NULL != pMoviePlay);  
    复制代码

    1. pCommMoviePlay = pMoviePlay->pCommMoviePlay;  
    复制代码
    1. pCommMoviePlay->play(pCommMoviePlay->hFile);  
    复制代码
  • }
    最后的工作就是对差别的hFile举行play的实际操作,写简单一点就是,
    [cpp] view plaincopy
  • void play_avi_file(HANDLE hFile)
  • {
    1. printf("play avi file!\n");  
    复制代码
  • }

  • void play_rmvb_file(HANDLE hFile)
  • {
    1. printf("play rmvb file!\n");  
    复制代码
  • }

  • void play_mpeg_file(HANDLE hFile)
  • {
    1. printf("play mpeg file!\n");  
    复制代码
  • }
十二、C语言和设计模式(适配器模式)
现在的生存当中,我们离不开各种电子工具。什么笔记本电脑、手机、mp4啊,都离不开充电。既然是充电,那么就必要用到充电器。其实从根本上来说,充电器就是一个个平凡的适配器。什么叫适配器呢,就是把220v、50hz的交流电压编程5~12v的直流电压。充电器就干了这么一件事变。
那么,这样的一个充电适配器,我们应该怎么用c++形貌呢?
[cpp] view plaincopy

  • class voltage_12v
  • {
  • public:
    1. voltage_12v() {}  
    复制代码
    1. virtual ~voltage_12v() {}  
    复制代码
    1. virtual void request() {}  
    复制代码
  • };

  • class v220_to_v12
  • {
  • public:
    1. v220_to_v12() {}  
    复制代码
    1. ~v220_to_v12() {}  
    复制代码
    1. void voltage_transform_process() {}  
    复制代码
  • };

  • class adapter: public voltage_12v
  • {
    1. v220_to_v12* pAdaptee;  
    复制代码

  • public:
    1. adapter() {}  
    复制代码
    1. ~adapter() {}  
    复制代码

    1. void request()   
    复制代码
    1. {  
    复制代码
    1.     pAdaptee->voltage_transform_process();  
    复制代码
    1. }  
    2.   
    复制代码
  • };
    通过上面的代码,我们其实可以这样理解。类voltage_12v表现我们的终极目标就是为了获得一个12v的直流电压。当然获得12v可以有许多的方法,利用适配器转换仅仅是其中的一个方法。adapter表现适配器,它自己不能实现220v到12v的转换工作,以是必要调用类v220_to_v12的转换函数。以是,我们利用adapter获得12v的过程,其实就是调用v220_to_v12函数的过程。
    不外,既然我们的主题是用c语言来编写适配器模式,那么我们就要实现最初的目标。这其实也不难,关键一步就是界说一个Adapter的数据布局。然后把全部的Adapter工作都由Adaptee来做,就是这么简单。不知我说明白了没有?
    [cpp] view plaincopy
  • typdef struct _Adaptee
  • {
    1. void (*real_process)(struct _Adaptee* pAdaptee);  
    复制代码
  • }Adaptee;

  • typedef struct _Adapter
  • {
    1. void* pAdaptee;  
    复制代码
    1. void (*transform_process)(struct _Adapter* pAdapter);  
    复制代码

  • }Adapter;
十三、 C语言和设计模式(装饰模式)
装饰模式是比较好玩,也比较故意义。其实就我个人看来,它和责任链还是蛮像的。只不外一个是比较判断,一个是迭代处理惩罚。装饰模式就是那种迭代处理惩罚的模式,关键在哪呢?我们可以看看数据布局。
[cpp] view plaincopy

  • typedef struct _Object
  • {
    1. struct _Object* prev;  
    复制代码

    1. void (*decorate)(struct _Object* pObject);  
    复制代码
  • }Object;
    装饰模式最经典的地方就是把pObject这个值放在了数据布局里面。当然,装饰模式的奥妙还不仅仅在这个地方,还有一个地方就是迭代处理惩罚。我们可以自己任意写一个decorate函数试试看,
    [cpp] view plaincopy
  • void decorate(struct _Object* pObeject)
  • {
    1. assert(NULL != pObject);  
    复制代码

    1. if(NULL != pObject->prev)  
    复制代码
    1.      pObject->prev->decorate(pObject->prev);  
    复制代码

    1. printf("normal decorate!\n");  
    复制代码
  • }
    以是,装饰模式的最紧张的两个方面就表现在:prev参数和decorate迭代处理惩罚。
    十四、 C语言和设计模式(享元模式)
    享元模式看上去有点玄乎,但是其实也没有那么复杂。我们还是用示例说话。好比说,各人在使用电脑的使用应该少不了使用WORD软件。使用WORD呢, 那就少不了设置模板。什么模板呢,好比说标题的模板,正文的模板等等。这些模板呢,又包罗许多的内容。哪些方面呢,好比说字体、标号、字距、行距、巨细等等。
    [cpp] view plaincopy
  • typedef struct _Font
  • {
    1. int type;  
    复制代码
    1. int sequence;  
    复制代码
    1. int gap;  
    复制代码
    1. int lineDistance;  
    复制代码

    1. void (*operate)(struct _Font* pFont);  
    复制代码

  • }Font;
    上面的Font表现了各种Font的模板形式。以是,下面的方法就是定制一个FontFactory的布局。
    [cpp] view plaincopy
  • typedef struct _FontFactory
  • {
    1. Font** ppFont;  
    复制代码
    1. int number;  
    复制代码
    1. int size;  
    复制代码

    1. Font* GetFont(struct _FontFactory* pFontFactory, int type, int sequence, int gap, int lineDistance);  
    复制代码
  • }FontFactory;
    这里的GetFont即使对当前的Font举行判断,如果Font存在,那么返回;否则创建一个新的Font模式。
    [cpp] view plaincopy
  • Font* GetFont(struct _FontFactory* pFontFactory, int type, int sequence, int gap, int lineDistance)
  • {
    1. int index;  
    复制代码
    1. Font* pFont;  
    复制代码
    1. Font* ppFont;  
    复制代码

    1. if(NULL == pFontFactory)  
    复制代码
    1.      return NULL;  
    复制代码

    1. for(index = 0; index < pFontFactory->number; index++)  
    复制代码
    1. {  
    复制代码
    1.     if(type != pFontFactory->ppFont[index]->type)  
    复制代码
    1.         continue;  
    复制代码

    1.     if(sequence != pFontFactory->ppFont[index]->sequence)  
    复制代码
    1.         continue;  
    复制代码

    1.     if(gap != pFontFactory->ppFont[index]->gap)  
    复制代码
    1.         continue;  
    复制代码

    1.     if(lineDistance != pFontFactory->ppFont[index]->lineDistance)  
    复制代码
    1.          continue;  
    复制代码

    1.     return pFontFactory->ppFont[index];  
    复制代码
    1. }  
    2.    
    复制代码

    1. pFont = (Font*)malloc(sizeof(Font));  
    复制代码
    1. assert(NULL != pFont);  
    复制代码
    1. pFont->type = type;  
    复制代码
    1. pFont->sequence = sequence;  
    复制代码
    1. pFont->gap = gap;  
    复制代码
    1. pFont->lineDistance = lineDistance;  
    复制代码

    1. if(pFontFactory-> number < pFontFactory->size)  
    复制代码
    1. {  
    复制代码
    1.     pFontFactory->ppFont[index] = pFont;  
    复制代码
    1.     pFontFactory->number ++;  
    复制代码
    1.     return pFont;  
    复制代码
    1. }  
    复制代码

    1. ppFont = (Font**)malloc(sizeof(Font*) * pFontFactory->size * 2);  
    复制代码
    1. assert(NULL != ppFont);  
    复制代码
    1. memmove(ppFont, pFontFacoty->ppFont, pFontFactory->size);  
    复制代码
    1. free(pFontFactory->ppFont);  
    复制代码
    1. pFontFactory->size *= 2;  
    复制代码
    1. pFontFactory->number ++;  
    复制代码
    1. ppFontFactory->ppFont = ppFont;  
    复制代码
    1. return pFont;         
    复制代码
  • }
十五、 C语言和设计模式(代理模式)
代理模式是一种比较故意思的设计模式。它的根本思路也不复杂。举个例子来说,以前在学校上网的时候,并不是每一台pc都有上网的权限的。好比说,现在有pc1、pc2、pc3,但是只有pc1有上网权限,但是pc2、pc3也想上网,此时应该怎么办呢?
此时,我们必要做的就是在pc1上开启代理软件,同时把pc2、pc3的IE代理指向pc1即可。这个时候,如果pc2大概pc3想上网,那么报文会先指向pc1,然后pc1把Internet传回的报文再发给pc2大概pc3。这样一个代理的过程就完成了整个的上网过程。
在说明完整的过程之后,我们可以思量一下软件应该怎么编写呢?
[cpp] view plaincopy

  • typedef struct _PC_Client
  • {
    1. void (*request)();  
    复制代码
  • }PC_Client;

  • void ftp_request()
  • {
    1. printf("request from ftp!\n");  
    复制代码
  • }

  • void http_request()
  • {
    1. printf("request from http!\n");  
    复制代码
  • }

  • void smtp_request()
  • {
    1. printf("request from smtp!\n");  
    复制代码
  • }
    这个时候,代理的操作应该怎么写呢?怎么处理惩罚来自各个协议的哀求呢?
    [cpp] view plaincopy
  • typedef struct _Proxy
  • {
    1. PC_Client* pClient;  
    复制代码
  • }Proxy;

  • void process(Proxy* pProxy)
  • {
    1. assert(NULL != pProxy);  
    复制代码

    1. pProxy->pClient->request();  
    复制代码
  • }
十六、C语言和设计模式(外观模式)
外观模式是比较简单的模式。它的目标也是为了简单。什么意思呢?举个例子吧。以前,我们逛街的时候吃要到小吃一条街,购物要到购物一条街,看书、看影戏要到文化一条街。那么有没有这样的地方,既可以吃喝玩乐,同时相互又靠得比较近呢。其实,这就是清闲广场,遍布天下的万达广场就是干了这么一件事。
起首,我们原来是怎么做的。
[cpp] view plaincopy

  • typedef struct _FoodSteet
  • {
    1. void (*eat)();  
    复制代码
  • }FoodStreet;

  • void eat()
  • {
    1. printf("eat here!\n");  
    复制代码
  • }

  • typedef struct _ShopStreet
  • {
    1. void (*buy)();  
    复制代码
  • }ShopStreet;

  • void buy()
  • {
    1. printf("buy here!\n");  
    复制代码
  • }

  • typedef struct _BookStreet
  • {
    1. void (*read)();  
    复制代码
  • }BookStreet;

  • void read()
  • {
    1. printf("read here");  
    复制代码
  • }
    下面,我们就要在一个plaza里面完成全部的项目,怎么办呢?
    [cpp] view plaincopy
  • typedef struct _Plaza
  • {
    1. FoodStreet* pFoodStreet;  
    复制代码
    1. ShopStreet* pShopStreet;  
    复制代码
    1. BookStreet* pBookStreet;  
    复制代码

    1. void (*play)(struct _Plaza* pPlaza);   
    复制代码
  • }Plaza;

  • void play(struct _Plaza* pPlaza)
  • {
    1. assert(NULL != pPlaza);  
    复制代码

    1. pPlaza->pFoodStreet->eat();  
    复制代码
    1. pPlaza->pShopStreet->buy();  
    复制代码
    1. pPlaza->pBookStreet->read();  
    复制代码
  • }
十七、 C语言和设计模式(迭代器模式)
使用过C++的朋友大概对迭代器模式都不会太生疏。这重要是因为我们在编写代码的时候离不开迭代器,队列有迭代器,向量也有迭代器。那么,为什么要迭代器呢?这重要是为了提炼一种通用的数据访问方法。
好比说,现在有一个数据的容器,
[cpp] view plaincopy

  • typedef struct _Container
  • {
    1. int* pData;  
    复制代码
    1. int size;  
    复制代码
    1. int length;  
    复制代码

    1. Interator* (*create_new_interator)(struct _Container* pContainer);  
    复制代码
    1. int (*get_first)(struct _Container* pContainer);  
    复制代码
    1. int (*get_last)(struct _Container* pContainer);  
    复制代码

  • }Container;
    我们看到,容器可以创建迭代器。那什么是迭代器呢?
    [cpp] view plaincopy
  • typedef struct _Interator
  • {
    1. void* pVector;  
    复制代码
    1. int index;  
    复制代码

    1. int(* get_first)(struct _Interator* pInterator);   
    复制代码
    1. int(* get_last)(struct _Interator* pInterator);  
    复制代码
  • }Interator;
    我们看到,容器有get_first,迭代器也有get_first,这中间有什么区别?
    [cpp] view plaincopy
  • int vector_get_first(struct _Container* pContainer)
  • {
    1. assert(NULL != pContainer);  
    复制代码

    1. return pContainer->pData[0];  
    复制代码
  • }

  • int vector_get_last(struct _Container* pContainer)
  • {
    1. assert(NULL != pContainer);  
    复制代码

    1. return pContainer->pData[pContainer->size -1];  
    复制代码
  • }

  • int vector_interator_get_first(struct _Interator* pInterator)
  • {
    1. Container* pContainer;  
    复制代码
    1. assert(NULL != pInterator && NULL != pInterator->pVector);  
    复制代码

    1. pContainer = (struct _Container*) (pInterator->pVector);  
    复制代码
    1. return pContainer ->get_first(pContainer);  
    复制代码
  • }

  • int vector_interator_get_last(struct _Interator* pInterator)
  • {
    1. Container* pContainer;  
    复制代码
    1. assert(NULL != pInterator && NULL != pInterator->pVector);  
    复制代码

    1. pContainer = (struct _Container*) (pInterator->pVector);  
    复制代码
    1. return pContainer ->get_last(pContainer);  
    复制代码
  • }
    看到上面的代码之后,我们发现迭代器的操作实际上也是对容器的操作而已。
十八、 C语言和设计模式(抽象工厂模式)
前面我们写过的工厂模式实际上是对产品的抽象。对于差别的用户需求,我们可以给予差别的产品,而且这些产品的接口都是同等的。而抽象工厂呢?顾名思义,就是说我们的工厂是不一定的。怎么理解呢,举个例子。
假设有两个水果店都在卖水果,都卖苹果和葡萄。其中一个水果店买白苹果和白葡萄,另外一个水果店卖红苹果和红葡萄。以是说,对于水果店而言,只管都在卖水果,但是两个店卖的品种不一样。
既然水果不一样,那我们先界说水果。
[cpp] view plaincopy

  • typedef struct _Apple
  • {
    1. void (*print_apple)();  
    复制代码
  • }Apple;

  • typedef struct _Grape
  • {
    1. void (*print_grape)();  
    复制代码
  • }Grape;
    上面分别对苹果和葡萄举行了抽象,当然它们的具体函数也是不一样的。
    [cpp] view plaincopy
  • void print_white_apple()
  • {
    1. printf("white apple!\n");  
    复制代码
  • }

  • void print_red_apple()
  • {
    1. printf("red apple!\n");  
    复制代码
  • }

  • void print_white_grape()
  • {
    1. printf("white grape!\n");  
    复制代码
  • }

  • void print_red_grape()
  • {
    1. printf("red grape!\n");  
    复制代码
  • }
    完成了水果函数的界说。下面就该界说工厂了,和水果一样,我们也必要对工厂举行抽象处理惩罚。
    [cpp] view plaincopy
  • typedef struct _FruitShop
  • {
    1. Apple* (*sell_apple)();  
    复制代码
    1. Apple* (*sell_grape)();  
    复制代码
  • }FruitShop;
    以是,对于卖白苹果、白葡萄的水果店就该这样设计了,红苹果、红葡萄的水果店亦是如此。
    [cpp] view plaincopy
  • Apple* sell_white_apple()
  • {
    1. Apple* pApple = (Apple*) malloc(sizeof(Apple));  
    复制代码
    1. assert(NULL != pApple);  
    复制代码

    1. pApple->print_apple = print_white_apple;  
    复制代码
    1. return pApple;  
    复制代码
  • }

  • Grape* sell_white_grape()
  • {
    1. Grape* pGrape = (Grape*) malloc(sizeof(Grape));  
    复制代码
    1. assert(NULL != pGrape);  
    复制代码

    1. pGrape->print_grape = print_white_grape;  
    复制代码
    1. return pGrape;  
    复制代码
  • }
    这样,根本的框架就算搭建完成的,以后创建工厂的时候,
    [cpp] view plaincopy
  • FruitShop* create_fruit_shop(int color)
  • {
    1. FruitShop* pFruitShop = (FruitShop*) malloc(sizeof(FruitShop));  
    复制代码
    1. assert(NULL != pFruitShop);  
    复制代码

    1. if(WHITE == color)  
    复制代码
    1. {  
    复制代码
    1.      pFruitShop->sell_apple = sell_white_apple;  
    复制代码
    1.      pFruitShop->sell_grape = sell_white_grape;  
    复制代码
    1. }  
    复制代码
    1. else  
    复制代码
    1. {  
    复制代码
    1.     pFruitShop->sell_apple = sell_red_apple;  
    复制代码
    1.     pFruitShop->sell_grape = sell_red_grape;  
    复制代码
    1. }  
    复制代码

    1. return pFruitShop;  
    复制代码
  • }
十九、 C语言和设计模式(责任链模式)
责任链模式是很实用的一种实际方法。举个例子来说,我们寻常在公司里面不免不了报销流程。但是,我们知道公司里面每一级的领导的报批额度是不一样的。好比说,科长的额度是1000元,部长是10000元,总经理是10万元。
那么这个时候,我们应该怎么设计呢?其实可以这么理解。好比说,有人来找领导报销费用了,那么领导可以自己先看看自己能不能报。如果费用可以顺利报下来当然最好,可是万一报不下来呢?那就只能请示领导的领导了。
[cpp] view plaincopy

  • typedef struct _Leader
  • {
    1. struct _Leader* next;  
    复制代码
    1. int account;  
    复制代码

    1. int (*request)(strcut _Leader* pLeader, int num);   
    复制代码
  • }Leader;
    以是这个时候,我们起首必要设置额度和领导。
[cpp] view plaincopy

  • void set_account(struct _Leader* pLeader, int account)
  • {
    1. assert(NULL != pLeader);  
    复制代码

    1. pLeader->account = account;  
    复制代码
    1. return;  
    复制代码
  • }

  • void set_next_leader(const struct _Leader* pLeader, struct _Leader* next)
  • {
    1. assert(NULL != pLeader && NULL != next);  
    复制代码

    1. pLeader->next = next;  
    复制代码
    1. return;  
    复制代码
  • }
    此时,如果有一个员工过来报销费用,那么应该怎么做呢?假设此时的Leader是经理,报销额度是10万元。以是此时,我们可以看看报销的费用是不是小于10万元?少于这个数就OK,反之就得上报自己的领导了。
    [cpp] view plaincopy
  • int request_for_manager(struct _Leader* pLeader, int num)
  • {
    1. assert(NULL != pLeader && 0 != num);  
    复制代码

    1. if(num < 100000)  
    复制代码
    1.      return 1;  
    复制代码
    1. else if(pLeader->next)   
    复制代码
    1.      return pLeader->next->request(pLeader->next, num);     
    复制代码
    1. else  
    2.   
    复制代码
    1.     return 0;  
    复制代码
  • }
二十、 C语言和设计模式(工厂模式)
工厂模式是比较简单,也是比较好用的一种方式。根本上说,工厂模式的目标就根据差别的要求输出差别的产品。好比说吧,有一个生产鞋子的工厂,它能生产皮鞋,也能生产胶鞋。如果用代码设计,应该怎么做呢?
[cpp] view plaincopy

  • typedef struct _Shoe
  • {
    1. int type;  
    复制代码
    1. void (*print_shoe)(struct _Shoe*);  
    复制代码
  • }Shoe;
    就像上面说的,现在有胶鞋,那也有皮鞋,我们该怎么做呢?
    [cpp] view plaincopy
  • void print_leather_shoe(struct _Shoe* pShoe)
  • {
    1. assert(NULL != pShoe);  
    复制代码
    1. printf("This is a leather show!\n");  
    复制代码
  • }

  • void print_rubber_shoe(struct _Shoe* pShoe)
  • {
    1. assert(NULL != pShoe);  
    复制代码
    1. printf("This is a rubber shoe!\n");  
    复制代码
  • }
    以是,对于一个工厂来说,创建什么样的鞋子,就看我们输入的参数是什么?至于效果,那都是一样的。
    [cpp] view plaincopy
  • #define LEATHER_TYPE 0x01
  • #define RUBBER_TYPE 0x02

  • Shoe* manufacture_new_shoe(int type)
  • {
    1. assert(LEATHER_TYPE == type || RUBBER_TYPE == type);  
    复制代码

    1. Shoe* pShoe = (Shoe*)malloc(sizeof(Shoe));  
    复制代码
    1. assert(NULL != pShoe);  
    复制代码

    1. memset(pShoe, 0, sizeof(Shoe));  
    复制代码
    1. if(LEATHER_TYPE == type)  
    复制代码
    1. {  
    复制代码
    1.     pShoe->type == LEATHER_TYPE;  
    复制代码
    1.     pShoe->print_shoe = print_leather_shoe;  
    复制代码
    1. }  
    复制代码
    1. else  
    复制代码
    1. {  
    复制代码
    1.     pShoe->type == RUBBER_TYPE;  
    复制代码
    1.     pShoe->print_shoe = print_rubber_shoe;  
    复制代码
    1. }  
    复制代码

    1. return pShoe;  
    复制代码
  • }
二十一、 C语言和设计模式(之模板模式)
模板对于学习C++的同学,其实并不生疏。函数有模板函数,类也有模板类。那么这个模板模式是个什么情况?我们可以思考一下,模板的本质是什么。好比说,现在我们必要编写一个简单的比较模板函数。
[cpp] view plaincopy

  • template
  • int compare (type a, type b)
  • {
    1. return a > b ? 1 : 0;  
    复制代码
  • }
    模板函数提示我们,只要比较的逻辑是确定的,那么不管是什么数据类型,都会得到一个相应的效果。固然,这个比较的流程比较简单,即使没有采取模板函数也没有关系。但是,要是必要拆分的步调许多,那么又该怎么办呢?如果相通了这个题目,那么也就明白了什么是template模式。
    比方说,现在我们必要设计一个流程。这个流程有许多小的步调完成。然而,其中每一个步调的方法是多种多样的,我们可以许多选择。但是,全部步调构成的逻辑是唯一的,那么我们该怎么办呢?其实也简单。那就是在基类中除了流程函数外,其他的步调函数全部设置为virtual函数即可。
    [cpp] view plaincopy
  • class basic
  • {
  • public:
    1. void basic() {}  
    复制代码
    1. virtual ~basic() {}  
    复制代码
    1. virtual void step1() {}  
    复制代码
    1. virtual void step2() {}  
    复制代码
    1. void process()  
    复制代码
    1. {  
    复制代码
    1.     step1();  
    复制代码
    1.     step2();  
    复制代码
    1. }  
    复制代码
  • };
    basic的类说明白根本的流程process是唯一的,以是我们要做的就是对step1和step2举行改写。
    [cpp] view plaincopy
  • class data_A : public basic
  • {
  • public:
    1. data_A() {}  
    复制代码
    1. ~data_A() {}  
    复制代码
    1. void step1()   
    复制代码
    1. {  
    复制代码
    1.      printf("step 1 in data_A!\n");  
    复制代码
    1. }  
    复制代码

    1. void step2()  
    复制代码
    1. {  
    复制代码
    1.     printf("step 2 in data_A!\n");  
    复制代码
    1. }  
    复制代码
  • };
    以是,按照我个人的理解,这里的template重要是一种流程上的统一,细节实现上的分离。明白了这个头脑,那么用C语言来形貌template模式就不是什么难事了。
    [cpp] view plaincopy
  • typedef struct _Basic
  • {
    1. void* pData;  
    复制代码
    1. void (*step1) (struct _Basic* pBasic);  
    复制代码
    1. void (*step2) (struct _Basic* pBasic);  
    复制代码
    1. void (*process) (struct _Basic* pBasic);  
    复制代码
  • }Basic;
    因为在C++中process函数是直接继续的,C语言下面没有这个机制。以是,对于每一个process来说,process函数都是唯一的,但是我们每一次操作的时候还是要去复制一遍函数指针。而step1和step2是差别的,以是各种方法可以用来机动修改自己的处理惩罚逻辑,没有题目。
    [cpp] view plaincopy
  • void process(struct _Basic* pBasic)
  • {
    1. pBasic->step1(pBasic);  
    复制代码
    1. pBasic->step2(pBasic);  
    复制代码
  • }
二十二、C语言和设计模式(之组合模式)
组合模式听说去很玄乎,其实也并不复杂。为什么?各人可以先想一下数据布局里面的二叉树是怎么回事。为什么就是这么一个简单的二叉树节点既大概是叶节点,也大概是父节点?
[cpp] view plaincopy

  • typedef struct _NODE
  • {
    1. void* pData;  
    复制代码
    1. struct _NODE* left;  
    复制代码
    1. struct _NODE* right;  
    复制代码
  • }NODE;
    那什么时候是叶子节点,其实就是left、right为NULL的时候。那么如果它们不是NULL呢,那么很显着此时它们已经是父节点了。那么,我们的这个组合模式是怎么一个情况呢?
    [cpp] view plaincopy
  • typedef struct _Object
  • {
    1. struct _Object** ppObject;  
    复制代码
    1. int number;  
    复制代码
    1. void (*operate)(struct _Object* pObject);  
    复制代码

  • }Object;
    就是这么一个简单的数据布局,是怎么实现子节点和父节点的差别呢。好比说,现在我们必要对一个父节点的operate举行操作,此时的operate函数应该怎么操作呢?
    [cpp] view plaincopy
  • void operate_of_parent(struct _Object* pObject)
  • {
    1. int index;  
    复制代码
    1. assert(NULL != pObject);  
    复制代码
    1. assert(NULL != pObject->ppObject && 0 != pObject->number);  
    复制代码

    1. for(index = 0; index < pObject->number; index ++)  
    复制代码
    1. {  
    复制代码
    1.      pObject->ppObject[index]->operate(pObject->ppObject[index]);  
    复制代码
    1. }  
    复制代码
  • }
    当然,有了parent的operate,也有child的operate。至于是什么操作,那就看自己是怎么操作的了。
[cpp] view plaincopy

  • void operate_of_child(struct _Object* pObject)
  • {
    1. assert(NULL != pObject);  
    复制代码
    1. printf("child node!\n");  
    复制代码
  • }
    父节点也好,子节点也罢,一切的一切都是最后的应用。其实,用户的调用也非常简单,就这么一个简单的函数。
[cpp] view plaincopy

  • void process(struct Object* pObject)
  • {
    1. assert(NULL != pObject);  
    复制代码
    1. pObject->operate(pObject);  
    复制代码
  • }
二十三、C语言和设计模式(之原型模式)
原型模式本质上说就是对当前数据举行复制。就像变戏法一样,一个鸽子变成了两个鸽子,两个鸽子变成了三个鸽子,就这么一直变下去。在变的过程中,我们不必要思量具体的数据类型。为什么呢?因为差别的数据有自己的复制类型,而且每个复制函数都是虚函数。
用C++怎么编写呢,那就是先写一个基类,再编写一个子类。就是这么简单。
[cpp] view plaincopy

  • class data
  • {
  • public:
    1. data () {}  
    复制代码
    1. virtual ~data() {}  
    复制代码
    1. virtual class data* copy() = 0;  
    复制代码
  • };

  • class data_A : public data
  • {
  • public:
    1. data_A() {}  
    复制代码
    1. ~data_A() {}  
    复制代码
    1. class data* copy()  
    复制代码
    1. {  
    复制代码
    1.     return new data_A();  
    复制代码
    1. }  
    复制代码
  • };

  • class data_B : public data
  • {
  • public:
    1. data_B() {}  
    复制代码
    1. ~data_B() {}  
    复制代码
    1. class data* copy()  
    复制代码
    1. {  
    复制代码
    1.     return new data_B();  
    复制代码
    1. }  
    复制代码
  • };
    那怎么使用呢?其实只要一个通用的调用接口就可以了。
    [cpp] view plaincopy
  • class data* clone(class data* pData)
  • {
    1. return pData->copy();  
    复制代码
  • }
    就这么简单的一个技巧,对C来说,当然也不是什么难事。
    [cpp] view plaincopy
  • typedef struct _DATA
  • {
    1. struct _DATA* (*copy) (struct _DATA* pData);  
    复制代码
  • }DATA;
    假设也有这么一个类型data_A,
    [cpp] view plaincopy
  • DATA data_A = {data_copy_A};
    既然上面用到了这个函数,以是我们也要界说啊。
    [cpp] view plaincopy
  • struct _DATA* data_copy_A(struct _DATA* pData)
  • {
    1. DATA* pResult = (DATA*)malloc(sizeof(DATA));  
    复制代码
    1. assert(NULL != pResult);  
    复制代码
    1. memmove(pResult, pData, sizeof(DATA));  
    复制代码
    1. return pResult;  
    复制代码
  • };
    使用上呢,当然也不含糊。
    [cpp] view plaincopy
  • struct _DATA* clone(struct _DATA* pData)
  • {
    1. return pData->copy(pData);  
    复制代码
  • };
二十四、C语言和设计模式(之单件模式)
有过面试履历的朋友,大概对设计模式有点熟悉的朋友,都会对单件模式不生疏。对许多面试官而言,单件模式更是他们面试的保留项目。其实,我倒认为,单件模式算不上什么设计模式。最多也就是个技巧。
单件模式要是用C++写,一般这么写。
[cpp] view plaincopy

  • #include <string.h>
  • #include <assert.h>

  • class object
  • {
  • public:
    1. static class object* pObject;  
    复制代码

    1. static object* create_new_object()  
    复制代码
    1. {  
    复制代码
    1.     if(NULL != pObject)  
    复制代码
    1.         return pObject;  
    复制代码

    1.     pObject = new object();  
    复制代码
    1.     assert(NULL != pObject);  
    复制代码
    1.     return pObject;  
    复制代码
    1. }  
    复制代码

  • private:
    1. object() {}  
    复制代码
    1. ~object() {}  
    复制代码
  • };

  • class object* object::pObject = NULL;
    单件模式的技巧就在于类的构造函数是一个私有的函数。但是类的构造函数又是必须创建的?怎么办呢?那就只有动用static函数了。我们看到static里面调用了构造函数,就是这么简单。
    [cpp] view plaincopy
  • int main(int argc, char* argv[])
  • {
    1. object* pGlobal = object::create_new_object();  
    复制代码
    1. return 1;  
    复制代码
  • }
    上面说了C++语言的编写方法,那C语言怎么写?其实也简单。各人也可以试一试。
    [cpp] view plaincopy
  • typedef struct _DATA
  • {
    1. void* pData;  
    复制代码
  • }DATA;

  • void* get_data()
  • {
    1. static DATA* pData = NULL;  
    复制代码

    1. if(NULL != pData)  
    复制代码
    1.     return pData;  
    复制代码

    1. pData = (DATA*)malloc(sizeof(DATA));  
    复制代码
    1. assert(NULL != pData);  
    复制代码
    1. return (void*)pData;  
    复制代码
  • }
二十五、C语言和设计模式(之开篇)
关于软件设计方面的书许多,好比《重构》,好比《设计模式》。至于软件开发方式,那就更多了,什么极限编程、精益方法、敏捷方法。随着时间的推移,许多的方法又会被重新提出来。
  1. 其实,就我个人看来,不管什么方法都离不开人。一个人写不出二叉树,你怎么让他写?敏捷吗?你写一行,我写一行。还是迭代?写三行,删掉两行,再写三行。项目的成功是偶然的,但是项目的失败却有很多原因,管理混乱、需求混乱、设计低劣、代码质量差、测试不到位等等。就软件企业而言,没有比优秀的文化和出色的企业人才更重要的了。
  2. 从软件设计层面来说,一般来说主要包括三个方面:
  3. (1)软件的设计受众,是小孩子、老人、女性,还是专业人士等等;
  4. (2)软件的基本设计原则,以人为本、模块分离、层次清晰、简约至上、适用为先、抽象基本业务等等;
  5. (3)软件编写模式,比如装饰模式、责任链、单件模式等等。
  6. 从某种意义上说,设计思想构成了软件的主题。软件原则是我们在开发中的必须遵循的准绳。软件编写模式是开发过程中的重要经验总结。灵活运用设计模式,一方面利于我们编写高质量的代码,另一方面也方便我们对代码进行维护。毕竟对于广大的软件开发者来说,软件的维护时间要比软件编写的时间要多得多。编写过程中,难免要有新的需求,要和别的模块打交道,要对已有的代码进行复用,那么这时候设计模式就派上了用场。我们讨论的主题其实就是设计模式。
  7. 讲到设计模式,人们首先想到的语言就是c#或者是java,最不济也是c++,一般来说没有人会考虑到c语言。其实,我认为设计模式就是一种基本思想,过度美化或者神化其实没有必要。其实阅读过linux kernel的朋友都知道,linux虽然自身支持很多的文件系统,但是linux自身很好地把这些系统的基本操作都抽象出来了,成为了基本的虚拟文件系统。
  8. 举个例子来说,现在让你写一个音乐播放器,但是要支持的文件格式很多,什么ogg,wav,mp3啊,统统要支持。这时候,你会怎么编写呢?如果用C++语言,你可能会这么写。
复制代码
[cpp] view plaincopy

  • class music_file
  • {
    1. HANDLE hFile;  
    复制代码

  • public:
    1. void music_file() {}  
    复制代码
    1. virtual ~music_file() {}  
    复制代码
    1. virtual void read_file() {}  
    复制代码
    1. virtual void play() {}  
    复制代码
    1. virtual void stop() {}  
    复制代码
    1. virtual void back() {}  
    复制代码
    1. virtual void front() {}  
    复制代码
    1. virtual void up() {}  
    复制代码
    1. virtual void down() {}  
    2.    
    复制代码
  • };
    其实,你想想看,如果用C语言能够完成相同的抽象操作,那不是效果一样的吗?
[cpp] view plaincopy

  • typedef struct _music_file
  • {
    1. HANDLE hFile;  
    复制代码
    1. void (*read_file)(struct _music_file* pMusicFile);  
    复制代码
    1. void (*play)(struct _music_file* pMusicFile);  
    复制代码
    1. void (*stop)(struct _music_file* pMusicFile);  
    复制代码
    1. void (*back)(struct _music_file* pMusicFile);  
    复制代码
    1. void (*front)(struct _music_file* pMusicFile);  
    复制代码
    1. void (*down)(struct _music_file* pMusicFile);  
    复制代码
    1. void (*up)(struct _music_file* pMusicFile);            
    复制代码
  • }music_file;
    当然,上面的例子比较简单,但是也能说明一些题目。写这篇文章的目标一是希望和朋友们共同学习模式的相干内容,另一方面也希望朋友们能够活学活用,既不要迷信权威,也不要妄自菲薄。只要付出努力,付出汗水,肯定会有收获的。有些大环境你改变不了,那就从改变自己开始。万丈高楼平地起,一步一个脚迹才能真真实实学到东西。如果盲目崇拜,言必google、微软、apple,那么除了带来几个唾沫星,还能有什么受用呢?无非白费了口舌而已。
    希望和各人共勉。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

麻花痒

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表