最近在公司分享了下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. Apache Hadoop学习笔记一

    官网:http://hadoop.apache.org/ 1 什么是Hadoop? Apache™Hadoop®项目开发了用于可靠,可扩展的分布式计算的开源软件. Apache Hadoop软件库是一 ...

  2. svn 的权限配置

    #分配用户所属组 g_admin=admin g_ui=zhangsan,lisi g_code=wangwu g_test=zhaoliu,qianqi #分配目录权限 #表示项目根目录 [/] @ ...

  3. 关于分布式版本控制系统Git与集中式版本控制系统SVN的区别

    我觉得最最主要的区别就是:分布式Git主要是在本地有各个历史版本,在不联网的时候,也可以更新到最新版本和查看过去的版本,而集中式SVN是所有人都将版本上传到中央服务器,当出现断网情况的时候,用户只有一 ...

  4. WPF前台界面显示“未将对象引用设置到对象的实例”

    在做即时通信项目中,使用WPF的MVVM模式,如果在前台绑定VM,经常会显示波浪线,鼠标放上去提示未将对象引用设置到对象的实例,但程序能正常运行,后来发现如果前台不绑定VM,在后台cs里绑定就不会出现 ...

  5. HIT2019春软件构造->Git&Github学习笔记

    由于软件构造课程需要,学习使用git,以下作为学习笔记. 一.Git初始化及仓库创建和操作  1.基本信息设置(设置签名)  命令        项目级别/仓库级别:仅在当前本地库范围内有效 git ...

  6. 将多窗体应用程序改造为仿Chrome形式的简易方法

    需求 在我们现有的ERP应用中,他是基于WinForm设计的,在早期的设计中,我们每打开一个作业,就会新建一个窗口,就像这样: 当我们打开很多的作业时,用户要通过Windows的任务栏慢慢找到,当然, ...

  7. mysql锁分析相关的几个系统视图

    1.infomation_schema.innodb_lock_waits+-------------------+-------------+------+-----+---------+----- ...

  8. 了解计算机与操作系统发展阶段以及android操作系统的发展史

    计算机与操作系统发展阶段 计算机的发展: 第一代(1946-1957年),电子管计算机 第二代(1958-1964年),晶体管计算机 第三代  (1964—1970年),集成电路数字机 第四代 (19 ...

  9. CouchDB客户端开发—Java版

    在Fedora上安装CouchDB: yum update yum install couchdb 修改/etc/couchdb下local.ini文件: port = 5984bind_addres ...

  10. maven到Gradle,一些对比和分享

    Gradle作为一款基于Groovy语言的构建工具,已经吸引众多的ant,maven使用者转投gradle的怀抱,和Gradle相比,ant显得冗余复杂,maven显得有些死板落后,而gradle基于 ...