設計模式的C語言應用-非典型模式-第十章
上一章為止,C語言里顯性和隱性的設計模式都已經介紹完了。
非典型模式章節開始介紹23種設計模式里在C語言退化的,不適用的。這些模式在使用中很難想到其實也是一種設計模式,代碼的實現也沒有什么特點。開發人員在設計時并不需要特意考慮這些模式,隨遇而安即可。
了解這些模式,只是加強一下開發人員的全局觀,在開發中能潤物無聲的應用和衍生。
原型模式(Prototype) 介紹
某些對象的結構比較復雜,但是我們又需要頻繁的使用它們。通過復制這些原型創建新的對象。
比如寫一個內核發送大量數據包的程序,比較好的辦法就是做好一個標準數據包,然后不停的復制,再發送出去。
深復制和淺復制
熟悉內核網絡實現的人一定知道,如果按照復制數據包的做法,最好的辦法是使用skb_clone函數而不是skb_copy函數。原因是,內核里表示數據包由skb和data部分組成。Skb只是管理的句柄,而data是數據包的真實數據。如果是同樣的數據包發送,只需要復制句柄,保持對data的引用就可以。這個就是淺復制。
圖表 1淺復制skb_clone
可以看出,淺復制skb_clone只是復制了sk_buff句柄,而下面的packet data storage指向的是同一個。
如果發送數據包要按照順序變換數據包IP頭的序列號和校驗碼。那么就需要同時復制句柄和data作為新的數據包,使用skb_copy函數。
圖表 2深復制skb_copy
可以看出,深復制skb_copy同時復制了sk_buff句柄和下面的packet data storage。
單例模式(Singleton) 介紹
單例模式就是確保某一個類只有一個實例,并且提供一個全局訪問點。在C語言的實現中,最常見的使用方法有且僅有一個:作為全局變量存在的控制數據。在嵌入式驅動開發中經常使用,比如driver定義,device定義。例子如下。
static struct platform_driver dwc3_exynos_driver = {
.probe????????????????? = dwc3_exynos_probe,
.remove?????????????? = __devexit_p(dwc3_exynos_remove),
.driver????????????????? = {
.name??? = "exynos-dwc3",
},
};
在ISP里用一個全局變量保存camera的屬性,都可以算是單例模式。
但是C語言里,由于這種方法太常見,除了一個全局變量,也沒有別的代碼,所以從來沒有人認為這是一個設計模式。
組合模式(Composite)
組合模式也稱為合成模式,有時候又成為部分-整體(part-whole)模式。
先看看在面向對象里的定義。組合模式將對象組織到樹結構里,可以用來描述整體和部分的關聯。合成模式可以使客戶端將單純元素和符合元素同等看到。
用C語言翻譯上面的話,就是把數據按照樹結構組織起來,訪問的時候能將葉子節點和中間節點同等處理,用的是遞歸的方法。
剩下的,大家參考數據結構的書吧。在C里面,這東西算數據結構,不算設計模式。
享元模式(Flyweight)
享元模式以共享的方式支持大量的細粒度對象。享元模式把對象屬性分為內部狀態和外部狀態。內部狀態是對象本質屬性,不可改變。外部的可以隨著環境改變。
享元模式最常見的在編輯器的實現里。如字母a,內部狀態就是a本身,外部狀態是位置,字體。這樣就能共享一個a對象,在編輯器里實現不同的表現。
在C里,并沒有發現這個模式有什么應用的場景。如果有人知道,請留言。
工廠模式和抽象工廠模式(Factory)
工廠方法模式定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個,也就是說工廠方法模式讓實例化推遲到子類。
對于C開發者,工廠模式更通俗一點理解就是,客戶并不直接malloc一個對象A或者B,而是調用一個工廠函數,輸入A或者B的類型。由工廠函數返回對象A或者B
對于C語言,沒有類的約束,創建對象也不過是一個malloc。靠輸入不同的參數決定產生不同的對象,談不上模式。實際應用也很少。
抽象工廠模式用來成體系的對象,C語言也用不上。
工廠模式樣例代碼
cap_factory生產不同的帽子
#define RED_TYPE 0x01
#define BLUE_TYPE? 0x02
struct cap
{
int type;
void (*process_cap)(struct cap*);
};
void process_red_cap(struct cap* pcap)
{
printf("This is a red cap!\n");
}
void process_blue_cap(struct cap* pcap)
{
printf("This is a blue cap!\n");
}
struct cap* cap_factory(int type)
{
struct cap* pcap = (struct cap*)malloc(sizeof(struct cap));
memset(pcap, 0, sizeof(struct cap));
if(RED_TYPE == type)
{
pcap->type == RED_TYPE;
pcap->process_cap = process_red_cap;
}
else
{
pcap->type == BLUE_TYPE;
pcap->process_cap = process_blue_cap;
}
return pcap;
}
解釋器模式(Interpreter)介紹
解釋器模式就是定義語言的語法,并且建立一個解釋器來解釋該語言中的句子。比如用C寫一個xml語言的解析器,這個開發就算是解釋器模式。顯然,C里面這個算是一個開發項目,不是設計模式。
另外一個常見的使用場景是C語言學習課程里,編寫一個計算器。需要將用戶輸入的算式的字符串解析并表達出來。但是編程和語法上也沒有什么特殊的。
在正常項目里也許有少量的地方根據字符串的語法含義做一些處理,但是場景非常少,用有意義的字符串做為控制參數顯然不如用整數或者結構體。
迭代器模式(Iterator) 介紹
迭代器模式是將迭代元素的責任交給迭代器,而不是對象,可以在不需要知道該聚合對象的內部結構就可以實現該聚合對象的迭代。
比如一組元素,可能是鏈表組成的,可能是樹狀結構。可以寫一個迭代器函數,屏蔽具體元素組織結構的差異,遍歷全部的元素,那么就算迭代器模式。顯然,C里面并不太需要這種方式。一個元素的組織結構,是在設計時綜合考慮效率,內存空間,場景,就已經確定了。如果一定要實現迭代器,最多也就是封裝一個函數。在C實現里,這種也不算是設計模式,需求也不明顯。
備忘錄模式(Memento)介紹
備忘錄模式又叫做快照模式(shapshot)。在不破壞封裝的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態,這樣可以在以后將對象恢復到原先保存的狀態。
在vmware虛擬機上用過linux的人一定對快照功能非常清楚。在android之前,一般的嵌入式linux的代碼都不多,在性能強的vmware虛擬機上安裝linux編譯,調試就能完成絕大部分任務。對于寫內核程序的開發者而言,可能一點錯誤就導致內核崩潰,需要重啟。所以一般會在調試之前用vmware保存一個snapshot。崩潰之后不用重啟,直接恢復快照(snapshot)就原地滿血復活, 回到快照那一刻的狀態。
對于C語言,如果有的過程數據需要保留,那么小的用臨時變量,大的可以分配一片內存。一般規模和需求都很小。也沒有一個特別的操作可以稱為模式。這種使用只在低功耗,寄存器保存恢復時使用,但是實現上沒有任何特別的代碼,都是整片的賦值。由于寄存器的特殊性,基本上不用memcpy,曾經發生過bug,因為嵌入式系統下memcpy未必是按照通常理解的word賦值,而是替換庫文件的memcpy函數改寫之后的。
策略模式(Strategy)介紹
開發中可以通過很多種不同的方式來完成一件事情,這里的每一種方式都可以稱作為一種策略。比如計算ISP的自動曝光,有兩種不同的算法,也可以稱為不同的策略。策略模式就是可以算法和策略但是外界不需要修改的設計模式。很顯然,只要算法和其他組件間的接口保持一致就可以。替換自動曝光算法,外部不修改代碼就可以運行。
再比如,有一個算法比較復雜,還在開發的過程中,主流程里很可能用相同的接口進行打樁。樁和實際算法在運行時可以動態用函數指針動態配置,那么這個不算通常意義的算法更替,但也算是用到的策略模式的思想。但是很顯然,對于C語言,這種肯定不算是一種明顯的設計模式,而是一種函數或者功能替換,也沒有特別的語法和架構支持,最多也就是使用函數指針方便替換策略。
很多帖子和書都拿替換排序算法為例,
中介者模式(Mediator)介紹
中介者模式也翻譯成調停者模式,就是用一個中介對象來封裝一系列的對象交互,中介者使各對象不需要顯式地相互引用。
圖表 1 相互引用的模型
圖表 2中介者模式
在C里面,這個也很難算是一種設計模式,只能算是一種思路吧。中介者模式和門面模式看起來有點像,但差別還是很明顯的。門面模式只是為了封裝系統內細節,對外提供套餐服務。而中介者模式并不提供套餐,而是隔離,協調各對象的行為。現實中,項目經理就擔任著中介者的角色。
橋接模式(Bridge)介紹
如果某個系統能夠從多個角度來進行分類,且每一種分類都可能會變化,那么我們需要做的就是講這多個角度分離出來,使得他們能獨立變化。橋接模式將繼承關系轉化成關聯關系。
更文藝的說法是,將”抽象化和實現化解耦”。 抽象化在面向對象就是將對象共同的性質抽取出去而形成類的過程。橋接模式中的所謂脫耦,就是指在一個軟件系統的抽象化和實現化之間使用關聯關系(組合或者聚合關系)而不是繼承關系,從而使兩者可以相對獨立地變化,這就是橋接模式的用意。
Java與模式書上舉了飛機的例子。飛機有兩個屬性,制造商(波音和空客)和用途(運輸機和客機)。書上把飛機作為抽象類,制造商作為具體實現類。不過如果再增加一個旋翼和固定翼的屬性呢?橋梁模式沒法解決超過2個維度的分類集成問題。
C就沒有真正意義上的繼承,所以我覺得,純粹用面向對象繼承改關聯的思路看橋接模式比較局限,C不存在這個模式的需求。如果有不同的因素,那多維數組是一個選擇。
Java 嵌入式
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。