C 设计模式:装饰模式

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

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

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

 

1、基础知识

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

 1 //一、继承性
 2 
 3 typedef struct _Parent
 4 {
 5     int data_parent;
 6 }Parent;
 7 
 8 typedef struct _Child
 9 {
10     struct _Parent parent;
11     int data_child;
12 }Child;
13 
14 //二、封装性
15 
16 struct _Data;
17 
18 typedef void (*fProc)(struct _Data* pData);
19 
20 typedef struct _Data
21 {
22     int value;
23     fProc Process;
24 }Data;
25 
26 //三、多态
27 
28 typedef struct _Run
29 {
30     void* pData;
31     void (*fProc)(struct _Run* pRun);
32 }Run;

 

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

 1 typedef struct _Object  
 2 {  
 3     struct _Object* prev;  
 4   
 5     void (*decorate)(struct _Object* pObject);  
 6 }Object;  
 7 
 8 void decorate(struct _Object* pObeject)  
 9 {  
10     assert(NULL != pObject);  
11   
12     if(NULL != pObject->prev)  
13         pObject->prev->decorate(pObject->prev);  
14   
15     printf("normal decorate!\n");  
16 }  

 

2、讲个故事

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

 1 typedef struct _SchoolRpt
 2 {
 3     void (*Report)();
 4     void (*Sign)(char* name);
 5 }
 6 
 7 void Report()
 8 {
 9     printf("我此次考了:语文62 数学65 体育98 天然63 \n");
10 }
11 
12 void Sign(char* name)
13 {
14     printf("家长签名:%s \n", name);
15 }
16 
17 int main()
18 {
19     SchoolRpt sr = {Report, Sign};
20     
21     sr.Report();
22     
23     return 0;
24 }
25 
26 /*
27 Output:
28 
29 我此次考了:语文62 数学65 体育98 天然63
30 
31 ////////////挨打中/////////////
32 */

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

 

3、故事还得继续

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

这样,先告诉老爹此次最高分时多少,“看,最高分也不高,你们考的都很差,题难呢!”。对象

而后再说本身的成绩。blog

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

好办法,咱们试一试。

 1 typedef struct _SchoolRpt
 2 {
 3     void (*Report)();
 4     void (*Sign)(char* name);
 5 }
 6 
 7 void Report()
 8 {
 9     printf("我此次考了:语文62 数学65 体育98 天然63 \n");
10 }
11 
12 void ReportHighScore()
13 {
14     printf("最高分:语文82 数学81 体育100 天然79 \n");
15 }
16 
17 void ReportSort()
18 {
19     printf("排名:30 \n");
20 }
21 
22 void Sign(char* name)
23 {
24     printf("家长签名:%s \n", name);
25 }
26 
27 int main()
28 {
29     SchoolRpt sr = {Report, Sign};
30     
31     ReportHighScore();
32     sr.Report();
33     ReportSort();
34     
35     sr.Sign("FATHER");
36     
37     return 0;
38 }
39 
40 /*
41 Output:
42 
43 最高分:语文82 数学81 体育100 天然79
44 我此次考了:语文62 数学65 体育98 天然63
45 排名:30
46 家长签名:FATHER
47 */

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

 

 4、故事有时候会变

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

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

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

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

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

 1 //抽象组件
 2 typedef struct _iobject
 3 {
 4     struct _iobject* prev;
 5     
 6     void (*frame_creater)(struct _iobject* obj); //接口函数
 7 
 8     void (*report)();
 9 }Iobject;
10 
11 //初始化某个Iobject的变量
12 void init_iobject(Iobject* obj, void (*report)(), void (*frame_creater)(Iobject* m_obj))
13 {
14     obj->frame_creater = frame_creater;
15     obj->prev = NULL;
16     obj->report = report;
17 }
18 
19 //置current的prev值
20 void add_iobject(Iobject* current, Iobject* prev)
21 {
22     current->prev = prev;
23 }
24 
25 //接口函数
26 void decorator_frame_creater(struct _iobject* obj)
27 {
28     if(obj->prev != NULL)
29         obj->prev->frame_creater(obj->prev);
30     
31     obj->report();
32 }
33 
34 /* ============================================================= */
35 typedef struct _SchoolRpt
36 {
37     struct _iobject scoreRpt;
38     
39     void (*Sign)(char* name);
40 }SchoolRpt;
41 
42 void Report()
43 {
44     printf("我此次考了:语文62 数学65 体育98 天然63 \n");
45 }
46 
47 void Sign(char* name)
48 {
49     printf("家长签名:%s \n", name);
50 }
51 
52 //装饰者
53 Iobject HighScoreDecorator;
54 Iobject SortDecorator;
55 
56 void ReportHighScore()
57 {
58     printf("最高分:语文82 数学81 体育100 天然79 \n");
59 }
60 
61 void ReportSort()
62 {
63     printf("排名:30 \n");
64 }
65 
66 int main()
67 {
68     SchoolRpt father = {{}, Sign};
69     
70     //老爹看报告前,得作些准备工做
71     Iobject *sr = &((Iobject)father);
72     
73     init_iobject(sr, Report, decorator_frame_creater);
74     init_iobject(&HighScoreDecorator, ReportHighScore, decorator_frame_creater);
75     init_iobject(&SortDecorator, ReportSort, decorator_frame_creater);
76     
77     //快加上装饰
78     add_iobject(&SortDecorator, sr);
79     add_iobject(sr, &HighScoreDecorator);
80     
81     //当心翼翼拿给老爹
82     sr->frame_creater(sr);
83     
84     //老爹签名
85     father.Sign("FATHER");
86     
87     return 0;
88 }
89 
90 /*
91 Output:
92 
93 最高分:语文82 数学81 体育100 天然79
94 我此次考了:语文62 数学65 体育98 天然63
95 排名:30
96 家长签名:FATHER
97 */

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

 

5、装饰模式

装饰者模式

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

 

意图:

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

 

设计原则:

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

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

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

 

要点:

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

2. 能够用一个或多个装饰者包装一个对象。

3. 装饰者能够在所委托被装饰者的行为以前或以后,加上本身的行为,以达到特定的目的。

4. 对象能够在任什么时候候被装饰,因此能够在运行时动态的,不限量的用你喜欢的装饰者来装饰对象。

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

6. 装饰者通常对组件的客户是透明的,除非客户程序依赖于组件的具体类型。在实际项目中能够根据须要为装饰者添加新的行为,作到“半透明”装饰者。

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

相关文章
相关标签/搜索