本文引用自本人公众号文章:
嵌入式开发中的两点编程思想
C语言也很讲究设计模式?一文讲透
包含如下:
01)C语言和设计模式(继承、封装、多态)
02)C语言和设计模式(访问者模式)
03)C语言和设计模式(状态模式)
04)C语言和设计模式(命令模式)
05)C语言和设计模式(解释器模式)
06)C语言和设计模式(备忘录模式)
07)C语言和设计模式(观察者模式)
08)C语言和设计模式(桥接模式)
09)C语言和设计模式(建造者模式)
10)C语言和设计模式(中介者模式)
11)C语言和设计模式(策略模式)
12)C语言和设计模式(适配器模式)
13)C语言和设计模式(装饰模式)
14)C语言和设计模式(享元模式)
15)C语言和设计模式(代理模式)
16)C语言和设计模式(外观模式)
17)C语言和设计模式(迭代器模式)
18)C语言和设计模式(抽象工厂模式)
19)C语言和设计模式(责任链模式)
20)C语言和设计模式(工厂模式)
21)C语言和设计模式(模板模式)
22)C语言和设计模式(组合模式)
23)C语言和设计模式(原型模式)
24)C语言和设计模式(单件模式)
25)C语言和设计模式(开篇)
-----------------------
01)C语言和设计模式(继承、封装、多态)
记得还在我们大学
C++第一门课的时候,老师就告诉我们说,C++是一门面向对象的语言。C++有三个最重要的特点,即继承、封装、多态。等到后来随着编码的增多和工作经验的积累,我也慢慢明白了面向对象的含义。可是,等我工作以后,使用的编程语言更多的是C语言,这时候我又想能不能把C语言变成面向对象的语言呢?等到后来通过思考和实践,我发现其实C语言也是可以面向对象的,也是可以应用设计模式的,关键就在于如何实现面向对象语言的三个重要属性。
(1)继承性
typedef struct _parent
{
int data_parent;
}Parent;
typedef struct _Child
{
struct _parent parent;
int data_child;
}Child;
在设计C语言继承性的时候,我们需要做的就是把基础数据放在继承的结构的首位置即可。这样,不管是数据的访问、数据的强转、数据的访问都不会有什么问题。
(2)封装性
struct _Data;
typedef void (*process)(struct _Data* pData);
typedef struct _Data
{
int value;
process pProcess;
}Data;
封装性的意义在于,函数和数据是绑在一起的,数据和数据是绑在一起的。这样,我们就可以通过简单的一个结构指针访问到所有的数据,遍历所有的函数。封装性,这是类拥有的属性,当然也是数据结构体拥有的属性。
(3)多态
typedef struct _Play
{
void* pData;
void (*start_play)(struct _Play* pPlay);
}Play;
多态,就是说用同一的
接口代码处理不同的数据。比如说,这里的Play结构就是一个通用的数据结构,我们也不清楚pData是什么数据,start_play是什么处理函数?但是,我们处理的时候只要调用pPlay->start_play(pPlay)就可以了。剩下来的事情我们不需要管,因为不同的接口会有不同的函数去处理,我们只要学会调用就可以了。
-----------------------
02)C语言和设计模式(访问者模式)
不知不觉当中,我们就到了最后一种设计模式,即访问者模式。访问者模式,听上去复杂一些。但是,这种模式用简单的一句话说,就是不同的人对不同的事物有不同的感觉。比如说吧,豆腐可以做成麻辣豆腐,也可以做成臭豆腐。可是,不同的地方的人未必都喜欢这两种豆腐。四川的朋友可能更喜欢辣豆腐,江浙的人就可能对臭豆腐更喜欢一些。那么,这种情况应该怎么用设计模式表达呢?
typedef struct _Tofu
{
int type;
void (*eat) (struct _Visitor* pVisitor, struct _Tofu* pTofu);
}Tofu;
typedef struct _Visitor
{
int region;
void (*process)(struct _Tofu* pTofu, struct _Visitor* pVisitor);
}Visitor;
就是这样一个豆腐,eat的时候就要做不同的判断了。
void eat(struct _Visitor* pVisitor, struct _Tofu* pTofu)
{
assert(NULL != pVisitor && NULL != pTofu);
pVisitor->process(pTofu, pVisitor);
}
既然eat的操作最后还是靠不同的visitor来处理了,那么下面就该定义process函数了。
void process(struct _Tofu* pTofu, struct _Visitor* pVisitor)
{
assert(NULL != pTofu && NULL != pVisitor);
if(pTofu->type == SP
ICY_FOOD && pVisitor->region == WEST ||
pTofu->type == STRONG_SMELL_FOOD && pVisitor->region == EAST)
{
printf("I like this food!\n");
return;
}
printf("I ha
te this food!\n");
}
-----------------------------------------------------
03)C语言和设计模式(状态模式)
状态模式是协议交互中使用得比较多的模式。比如说,在不同的协议中,都会存在启动、保持、中止等基本状态。那么怎么灵活地转变这些状态就是我们需要考虑的事情。假设现在有一个state,
typedef struct _State
{
void (*process)();
struct _State* (*change_state)();
}State;
说明一下,这里定义了两个变量,分别process函数和change_state函数。其中proces函数就是普通的数据操作,
void normal_process()
{
printf("normal process!\n");
}
change_state函数本质上就是确定下一个状态是什么。
struct _State* change_state()
{
State* pNextState = NULL;
pNextState = (struct _State*)malloc(sizeof(struct _State));
assert(NULL != pNextState);
pNextState ->process = next_process;
pNextState ->change_state = next_change_state;
return pNextState;
}
所以,在context中,应该有一个state变量,还应该有一个state变换函数。
typedef struct _Context
{
State* pState;
void (*change)(struct _Context* pContext);
}Context;
void context_change(struct _Context* pContext)
{
State* pPre;
assert(NULL != pContext);
pPre = pContext->pState;
pContext->pState = pPre->changeState();
free(pPre);
return;
}
评论