最近在公司分享了下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. Axure文本框验证和外部url的调用

    文本框的验证和外部url的调用: 场景: 当输入文本框中的内容是满足下面条件时:输入4-10的数字,页面会跳转到QQ注册(https://ssl.zc.qq.com/v3/index-chs.html ...

  2. Hadoop分布式文件系统HDFS的工作原理

    Hadoop分布式文件系统(HDFS)是一种被设计成适合运行在通用硬件上的分布式文件系统.HDFS是一个高度容错性的系统,适合部署在廉价的机器上.它能提供高吞吐量的数据访问,非常适合大规模数据集上的应 ...

  3. 导出MySql中的数据库 --Linux/Windows

    1.thanlon@thanlon-Ubuntu:~$ mysqldump -uroot -p mysql>db.sql “mysql”为数据库名,db.sql为导出的文件

  4. js vue 在页面中将摄像头放在一个标签里展示,(模仿手机拍照功能)

    1.HTML <video id="video" autoplay class="fileImg"></video> <canva ...

  5. 触发form表单的两种提交方式,submit和button的用法

    1.当输入用户名和密码为空的时候,需要判断.这时候就用到了校验用户名和密码,这个需要在jsp的前端页面写:有两种方法,一种是用submit提交.一种是用button提交. 方法一: 在jsp的前端页面 ...

  6. springcloud-zuul路由网关

    路由网关(zuul) 在微服务架构中,需要多个基础的服务治理组件,包括服务注册与发现.服务消费.负载均衡.断路器.智能 路由.配置管理等,由这个基础组件相互协作,共同组建了一个简单的微服务系统.一个简 ...

  7. 【C/C++】C++11 Move, Forward

    左值与右值 Lvalue:可以出现在 operator= 左边的 Rvalue:只能出现在operator= 右边的 ; int a = b; a = b; a = a + b; a + b = a; ...

  8. 集合框架之map

    Map实现类用于保存具有映射关系的数据.Map保存的每项数据都是key-value对,也就是由key和value两个值组成.Map里的key是不可重复的,key用户标识集合里的每项数据. Map提供了 ...

  9. 手机端页面自适应解决方案—rem布局进阶版

    手机端页面自适应解决方案—rem布局进阶版   https://www.jianshu.com/p/985d26b40199 注:本文转载之处:https://www.cnblogs.com/anni ...

  10. jieba 库

    jieba库是python 一个重要的第三方中文分词函数库,但需要用户自行安装. 一.jieba 库简介 (1) jieba 库的分词原理是利用一个中文词库,将待分词的内容与分词词库进行比对,通过图结 ...