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 ...
随机推荐
- Creed_颓知乎
题目背景 二轮省选前的一个最后周,Creed_还在颓知乎. 突然,她看到一个有趣的回答. 紧接着,Creed_点开了评论区,又看到了一个有趣的评论. Creed_想了一下,发现自己并不会,于是她又顺着 ...
- 蓝桥杯第六届省赛 手链样式 STL
小明有3颗红珊瑚,4颗白珊瑚,5颗黄玛瑙.他想用它们串成一圈作为手链,送给女朋友.现在小明想知道:如果考虑手链可以随意转动或翻转,一共可以有多少不同的组合样式呢? 分析:这个题首先一定要理解题意,转动 ...
- MongoVUE的table view视图不显示列标题
近来项目用到mongodb,遂装了个MongoVUE,当然是破解版的. 但是发现个小问题,就是table view视图下列标题文字标签不见了,Find的执行按钮也是空白一片: 开始以为破解的不彻底,重 ...
- 课堂小练习(complex类)
定义一个复数类Complex,使得下面的代码能够工作: Complex c1(3,5); //用复数3+5i初始化c1: Compex c2=4.5; //用实数4.5初始化c2 c ...
- fiddler安装及mock数据
1,fiddler安装,解决无法抓到https问题 可用本机的火狐浏览器测试,不行,就fiddler生成证书,拷到火狐里 在firefox中,选项->进入配置界面:高级-> 证书 -> ...
- jquery 判断浏览器版本
如果你也是Jquery最初的使用者,那么你一定经历过这样判断浏览器的时代:$.browser.msie && $.browser.version,你目前使用的组件里可能还有应用.但是J ...
- tomcat 7 启动报错:java.lang.NoSuchMethodError: javax.servlet.ServletContext.getSessionCookieConfig()Ljavax/servlet/SessionCookieConfig的解决
现象: tomcat 7 启动报错:java.lang.NoSuchMethodError: javax.servlet.ServletContext.getSessionCookieConfig() ...
- PS笔刷的使用
直接进入正文了! 第一步 打开你的ps,至少是CS6哦,没有安装包的可以去网上找,或者找我0.0. 第二步 将面板改为绘画功能. 第三步打开“窗口”调出“画笔”“画笔预设”“图层”等面板,“颜色”面板 ...
- GDAL——命令使用专题——ogrinfo命令
GDAL——命令使用专题——ogrinfo命令 前言 GDAL(Geospatial Data Abstraction Library)是一个在X/MIT许可协议下的开源栅格空间数据转换库.它利用抽象 ...
- Delphi 带星期几的日期格式化
把日期按日期+星期几的格式输出 方法1:DatetoStr + DayOfWeek计算 ,这种办法灵活,但计算量大,不再祥叙. 方法2:FormatDateTime 具体代码如下://这里需要用For ...