最近在公司分享了下C语言版的设计模式,记录一下吧。

参考:《设计模式之禅》中“装饰模式”章节。

上面书中是用C++来实现的,我使用了书中的例子,改用C语言来实现。

一、基础知识

面向对象最重要的三个特性,在C语言中大致的实现如下所示。

 //1、继承性

 typedef struct _Parent
{
int data_parent;
}Parent; typedef struct _Child
{
struct _Parent parent;
int data_child;
}Child; //2、封装性 struct _Data; typedef void (*fProc)(struct _Data* pData); typedef struct _Data
{
int value;
fProc Process;
}Data; //3、多态 typedef struct _Run
{
void* pData;
void (*fProc)(struct _Run* pRun);
}Run;

装饰模式,在C语言中的实现:

 typedef struct _Object
{
struct _Object* prev; void (*decorate)(struct _Object* pObject);
}Object; void decorate(struct _Object* pObeject)
{
assert(NULL != pObject); if(NULL != pObject->prev)
pObject->prev->decorate(pObject->prev); printf("normal decorate!\n");
}

二、讲个故事

很久很久以前,大概还是小学的时候,期末考试完,最可怕的事情就是:老师让把试卷拿回家里,让家长签字。

 typedef struct _SchoolRpt
{
void (*Report)();
void (*Sign)(char* name);
} void Report()
{
printf("我这次考了:语文62 数学65 体育98 自然63 \n");
} void Sign(char* name)
{
printf("家长签名:%s \n", name);
} int main()
{
SchoolRpt sr = {Report, Sign}; sr.Report(); return ;
} /*
Output: 我这次考了:语文62 数学65 体育98 自然63 ////////////挨打中/////////////
*/

得,这么耿直的直接拿给老爹看,一定得被啪啪啪。还想要签字?做梦!

三、故事还得继续

得想个办法呀。这个事情,跟写作文一样,得润色润色,不能太耿直。

这样,先告诉老爹这次最高分时多少,“看,最高分也不高,大家考的都不好,题难呢!”。

然后再说自己的成绩。

最后,再说下自己的班级排名,“其实,排名比往常还有点小进步的哦~”。

好办法,我们试一试。

 typedef struct _SchoolRpt
{
void (*Report)();
void (*Sign)(char* name);
} void Report()
{
printf("我这次考了:语文62 数学65 体育98 自然63 \n");
} void ReportHighScore()
{
printf("最高分:语文82 数学81 体育100 自然79 \n");
} void ReportSort()
{
printf("排名:30 \n");
} void Sign(char* name)
{
printf("家长签名:%s \n", name);
} int main()
{
SchoolRpt sr = {Report, Sign}; ReportHighScore();
sr.Report();
ReportSort(); sr.Sign("FATHER"); return ;
} /*
Output: 最高分:语文82 数学81 体育100 自然79
我这次考了:语文62 数学65 体育98 自然63
排名:30
家长签名:FATHER
*/

好嘞,成了,拿到了老爹的签名,少挨了一次打。开心~

四、故事有时候会变

但是呢,事情都不是绝对的。

有时候老爹心情比较好,只说了最高成绩,老爹就要签名了,还没来得及说自己的排名呢。

有时候老爹心情不太好,那得想更多的法子才行。

那得给每种场景都写个 方法吗?那得累死啦。

噔噔噔,装饰模式出场了:

 //抽象组件
typedef struct _iobject
{
struct _iobject* prev; void (*frame_creater)(struct _iobject* obj); //接口函数 void (*report)();
}Iobject; //初始化某个Iobject的变量
void init_iobject(Iobject* obj, void (*report)(), void (*frame_creater)(Iobject* m_obj))
{
obj->frame_creater = frame_creater;
obj->prev = NULL;
obj->report = report;
} //置current的prev值
void add_iobject(Iobject* current, Iobject* prev)
{
current->prev = prev;
} //接口函数
void decorator_frame_creater(struct _iobject* obj)
{
if(obj->prev != NULL)
obj->prev->frame_creater(obj->prev); obj->report();
} /* ============================================================= */
typedef struct _SchoolRpt
{
struct _iobject scoreRpt; void (*Sign)(char* name);
}SchoolRpt; void Report()
{
printf("我这次考了:语文62 数学65 体育98 自然63 \n");
} void Sign(char* name)
{
printf("家长签名:%s \n", name);
} //装饰者
Iobject HighScoreDecorator;
Iobject SortDecorator; void ReportHighScore()
{
printf("最高分:语文82 数学81 体育100 自然79 \n");
} void ReportSort()
{
printf("排名:30 \n");
} int main()
{
SchoolRpt father = {{}, Sign}; //老爹看报告前,得做些准备工作
Iobject *sr = &((Iobject)father); init_iobject(sr, Report, decorator_frame_creater);
init_iobject(&HighScoreDecorator, ReportHighScore, decorator_frame_creater);
init_iobject(&SortDecorator, ReportSort, decorator_frame_creater); //快加上装饰
add_iobject(&SortDecorator, sr);
add_iobject(sr, &HighScoreDecorator); //小心翼翼拿给老爹
sr->frame_creater(sr); //老爹签名
father.Sign("FATHER"); return ;
} /*
Output: 最高分:语文82 数学81 体育100 自然79
我这次考了:语文62 数学65 体育98 自然63
排名:30
家长签名:FATHER
*/

这样就好了,不同的场景,只需要配置不同的报告方式就好。再也不用担心老爹揍我啦,哈哈~(假的)。

五、装饰模式

装饰者模式

Decorator模式(别名Wrapper):动态将职责附加到对象上,若要扩展功能,装饰者提供了比继承更具弹性的代替方案。

意图:

动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。

设计原则:

1. 多用组合,少用继承。

利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。

2. 类应设计的对扩展开放,对修改关闭。

要点:

1. 装饰者和被装饰对象有相同的超类型。

2. 可以用一个或多个装饰者包装一个对象。

3. 装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定的目的。

4. 对象可以在任何时候被装饰,所以可以在运行时动态的,不限量的用你喜欢的装饰者来装饰对象。

5. 装饰模式中使用继承的关键是想达到装饰者和被装饰对象的类型匹配,而不是获得其行为。

6. 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。在实际项目中可以根据需要为装饰者添加新的行为,做到“半透明”装饰者。

7. 适配器模式的用意是改变对象的接口而不一定改变对象的性能,而装饰模式的用意是保持接口并增加对象的职责。

C 设计模式:装饰模式的更多相关文章

  1. 设计模式 装饰模式(Decorator)

    设计模式 装饰模式(Decorator) @author ixenos 装饰模式是什么 1.装饰模式以对客户端透明的方式对象的功能,是继承关系的一个替代方案,但装饰模式可以在不创造更多子类的情况下,对 ...

  2. c++设计模式----装饰模式

    前言 在实际开发时,你有没有碰到过这种问题:开发一个类,封装了一个对象的核心操作,而这些操作就是客户使用该类时都会去调用的操作:而有一些非核心的操作,可能会使用,也可能不会使用:现在该怎么办呢? 将这 ...

  3. Java设计模式---装饰模式

    装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰模式的结构 装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任.换言之,客户 ...

  4. C++设计模式——装饰模式

    前言 在实际开发时,你有没有碰到过这种问题:开发一个类,封装了一个对象的核心操作,而这些操作就是客户使用该类时都会去调用的操作:而有一些非核心的操作,可能会使用,也可能不会使用:现在该怎么办呢? 将这 ...

  5. 设计模式—装饰模式的C++实现

    这是Bwar在2009年写的设计模式C++实现,代码均可编译可运行,一直存在自己的电脑里,曾经在团队技术分享中分享过,现搬到线上来. 1. 装饰模式简述 1.1 目的 动态地给一个对象添加一些额外的职 ...

  6. 设计模式--装饰模式Decorate(结构型)

    一.装饰模式 动态地给一个对象添加额外的职责.就增加功能来说,装饰模式相比生成子类更为灵活.有时我们希望给某个对象而不是整个类添加一些功能. 二.UML图 1.Component(概念中提到的对象接口 ...

  7. [工作中的设计模式]装饰模式decorator

    一.模式解析 装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰模式的要点主要是: 1.需要对已有对象扩展新的功能,又不希望改变原有对 ...

  8. 深入浅出设计模式——装饰模式(Decorator Pattern)

    模式动机 一般有两种方式可以实现给一个类或对象增加行为: 继承机制,使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法.但是这种方法是静 ...

  9. Java设计模式-装饰模式(Decorator)

    顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下: Source类是被装饰类,Decorator类是一个 ...

  10. javascript设计模式-装饰模式

    装饰模式:在不改变原类(对象)和继承的情况下动态扩展对象功能,通过包装一个对象来实现一个新的具有原对象相同接口的新的对象.在设计原则中,有一条,多用组合,少用继承,装饰模式正是这一原则的体现. UML ...

随机推荐

  1. English Voice of <<Something just like this>>

    歌名:something just like this演唱:Chris Martin 词:Andrew Taggart,Chris Martin 曲:Andrew Taggart,Chris Mart ...

  2. zoj3223

    其实这题不超时完全是因为串长度太小,如果串够长,一次匹配后都要往上跳,复杂度是n^2的. #include <iostream> #include <cstdio> #incl ...

  3. cron定时任务

    1.确认系统安装了cron rpm -aq | grep crontabs 2.认识cron时间格式 3.生成定时任务 crontab -e #进入任务命令编辑模式 30 7,12,20 * * * ...

  4. zabbix报错gd、freetype、png、jpeg

    安装包位置:http://www.p-pp.cn/app/zabbix/ 1.安装freetype [root@localhost softs]# tar xf freetype-2.5.0.tar. ...

  5. Linux删除/boot后该如何恢复

    一.其实不光boot目录被删除,也有系统启动不起来等,一直因为/boot这个目录的的问题,今天就来解决一下 Centos 6 1.进入救援,先修复vmlinz(内核) chroot /mnt/sysi ...

  6. 安装weblogic

    附:wls1036_generic.jar 链接:https://pan.baidu.com/s/1W5g-SHeKL96yrOeDKJJoxw 提取码:vxft 注:以下安装步骤是一个前辈整理的,我 ...

  7. Matlab:正则Euler分裂

    函数文件1: function b=F(x0,h,u,tau) b(,)=x0()-u(); b(,)=x0()-u()+*h*1e8*cos(tau)*x0(); 函数文件2: function g ...

  8. Tor真的匿名和安全吗?——如果是http数据,则在出口节点容易被嗅探明文流量,这就是根本问题

    Tor真的匿名和安全吗? from:http://baham.github.io/04_03_torzhen-de-ni-ming-he-an-quan-ma-%3F.html 很多人相信Tor是完全 ...

  9. mysql插件的初始化

  10. A、B两个线程交替打印1 -- 100

    方案一:import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.u ...