C 设计模式:装饰模式
最近在公司分享了下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 设计模式:装饰模式的更多相关文章
- 设计模式 装饰模式(Decorator)
设计模式 装饰模式(Decorator) @author ixenos 装饰模式是什么 1.装饰模式以对客户端透明的方式对象的功能,是继承关系的一个替代方案,但装饰模式可以在不创造更多子类的情况下,对 ...
- c++设计模式----装饰模式
前言 在实际开发时,你有没有碰到过这种问题:开发一个类,封装了一个对象的核心操作,而这些操作就是客户使用该类时都会去调用的操作:而有一些非核心的操作,可能会使用,也可能不会使用:现在该怎么办呢? 将这 ...
- Java设计模式---装饰模式
装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰模式的结构 装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任.换言之,客户 ...
- C++设计模式——装饰模式
前言 在实际开发时,你有没有碰到过这种问题:开发一个类,封装了一个对象的核心操作,而这些操作就是客户使用该类时都会去调用的操作:而有一些非核心的操作,可能会使用,也可能不会使用:现在该怎么办呢? 将这 ...
- 设计模式—装饰模式的C++实现
这是Bwar在2009年写的设计模式C++实现,代码均可编译可运行,一直存在自己的电脑里,曾经在团队技术分享中分享过,现搬到线上来. 1. 装饰模式简述 1.1 目的 动态地给一个对象添加一些额外的职 ...
- 设计模式--装饰模式Decorate(结构型)
一.装饰模式 动态地给一个对象添加额外的职责.就增加功能来说,装饰模式相比生成子类更为灵活.有时我们希望给某个对象而不是整个类添加一些功能. 二.UML图 1.Component(概念中提到的对象接口 ...
- [工作中的设计模式]装饰模式decorator
一.模式解析 装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰模式的要点主要是: 1.需要对已有对象扩展新的功能,又不希望改变原有对 ...
- 深入浅出设计模式——装饰模式(Decorator Pattern)
模式动机 一般有两种方式可以实现给一个类或对象增加行为: 继承机制,使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法.但是这种方法是静 ...
- Java设计模式-装饰模式(Decorator)
顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下: Source类是被装饰类,Decorator类是一个 ...
- javascript设计模式-装饰模式
装饰模式:在不改变原类(对象)和继承的情况下动态扩展对象功能,通过包装一个对象来实现一个新的具有原对象相同接口的新的对象.在设计原则中,有一条,多用组合,少用继承,装饰模式正是这一原则的体现. UML ...
随机推荐
- Django 应用程序 + 模型 + 基本数据访问
如果你只是建造一个简单的web站点,那么可能你只需要一个app就可以了.如果是复杂的象 电子商务之类的Web站点,你可能需要把这些功能划分成不同的app,以便以后重用. 确实,你还可以不用创建app, ...
- 【转】 HDMI介绍与流程
转自:https://www.cnblogs.com/TaigaCon/p/3840653.html HDMI,全称为(High Definition Multimedia Interface)高清多 ...
- 容器虚拟网卡与网桥docker0虚拟网卡的veth pair的配对
一)基本知识: Docker 安装时会自动在 host 上创建三个网络:none,host,和bridge:详细说明可参考其它文档.我们可用 docker network ls 命令查看: 基于DRI ...
- Python 进度条原理
#进度条原理 import sys,time for i in range(50): sys.stdout.write("#")#标准输出 #若不能够按照时间一个一个依次显示,则代 ...
- mtcnn
1.widerface样本标签处理 图片名 x1 y1 x2 y2 x11 y11 x22 y22 多人脸框 # -*- coding: utf- -*- ""&qu ...
- document.documentElement.clientHeight和document.body.clientHeight区别
首先了解下document HTML DOM 节点 在 HTML DOM (Document Object Model) 中 , 每一个元素都是 节点: 文档是一个文档节点. 所有的HTML元素都是元 ...
- 一个axios的简单教程
转载于:https://www.jianshu.com/p/13cf01cdb81f 转载仅供个人学习 首先要明白的是axios是什么:axios是基于promise(诺言)用于浏览器和node.js ...
- PAT 1144 The Missing Number
1144 The Missing Number (20 分) Given N integers, you are supposed to find the smallest positive in ...
- xshell6 同时操作多个终端
当我们使用Xshell的时候,有时候需要同时建立多个会话,连接不同的服务器或者不同的用户,如何同时向所有会话发送同一指令呢?方法如下: 1.依次点击 查看 ---> 撰写 ---> 撰写 ...
- [luogu P2375] [NOI 2014] 动物园
[luogu P2375] [NOI 2014] 动物园 题目描述 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的真才实学向 ...