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. 適配器模式的用意是改變對象的接口而不必定改變對象的性能,而裝飾模式的用意是保持接口並增長對象的職責。

相關文章
相關標籤/搜索