1. 程式人生 > >宋寶華:Linux裝置驅動框架裡的設計模式之——模板方法(Template Method)

宋寶華:Linux裝置驅動框架裡的設計模式之——模板方法(Template Method)

本文系轉載,著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

作者: 宋寶華

來源: 微信公眾號linux閱碼場(id: linuxdev)


前言

《設計模式》這本經典的書裡面定義了20多種設計模式,雖然都是面向物件的,似乎需要C++、Java這樣的語言才能實現,但是根據筆者前面反覆強調的,Linux核心雖然是用C語言和組合語言寫成,但是其實也到處充滿了面向物件的設計。面向物件更多的是一種思想,而不是一個語言。我們可以用C語言實現極大的OO,Linux核心到處都有OO。

模版方法

比如,在Linux的裝置驅動框架中,就用了一種非常經典簡單的設計模式——模板方法(Template Method),當然還有一些其他的設計模式。而設計模式牛逼的地方在於,高手往往不經意之間已經用到了設計模式,甚至自己都不知道。如果高手沒有系統地學習過設計模式,這其實不見得是一個問題。這並不意味著它不懂設計模式,只是他自己都不知道自己用到了哪個模式。而設計模式學習的終極目的,當然也是忘記設計模式,這個跟練獨孤九劍沒什麼區別,到最後其實是無招勝有招。

模板方法這個模式,強調定義一個基類,這個基類實現了通用的流程和演算法。比如做一件事情需要經過step1()、step2()、step3()。那麼我們定義一個基類:

而其中的step1()、step2()、step3()、step4()具體如何實現則是因人而異,所以我們從baseClass類裡面,繼承出來的類裡面,實現step1()、step2()、step3()這樣的程式碼,override掉baseClass裡面的函式。

這樣的設計讓外部不關心derivedClass,因為流程和介面都是在基類的。而基類實現的doSomething()成員函式,是對外的介面。這個UML關係是非常簡單的:

驅動案例

在Linux裝置驅動裡面,大量存在類似的設計,我們以NAND為例子。在drivers/mtd/nand/nand_base.c這層裡面,定義了NAND的一些操作流程。

比如寫OOB的程式碼:

它這個裡面要走cmdfunc()、write_buf()、cmdfunc()、waitfunc()這些步驟,這些步驟,不管是全世界哪個NAND的硬體,都是一樣的通用的,但是具體的不同的NAND硬體控制器,實現這些步驟中涉及到的cmdfunc()等函式的實現方法卻因人而異。

譬如freescale的版本fsl_elbc_nand.c就是:

nand_base.c這個C檔案是NAND的中間層,它非常類似我們前面說的實現baseClass這一層的程式碼,nand_write_oob_std函式類似baseClass :: doSomething。而Linux驅動中定義的nand_chip的各個不同的NAND控制器,對nand_chip這個結構體中成員函式cmdfunc()、write_buf()等的實現則是各異的,類似derivedClass裡面override掉step1()、step2()。nand_chip定義在include/linux/mtd/nand.h:

這樣的設計,好處是非常明顯的。特定的硬體只用管與自身操作相關的事情,而通用的流程,都由nand_base搞定,最大程度上減小了具體例項的程式碼量,也最大程度上覆用了中間層的程式碼。

這樣的例子無處不在,比如我們在LCD的中間層:

後語

本文後語不搭前言,請見諒。最近有很多童鞋詢問筆者,做Linux驅動有沒有前途?筆者明確地告訴大家:根本沒有前途!但是前途是自己賺的,這依賴你從驅動進去,但是從更大的視角出來:

  1. 通過做驅動理解很多OO的架構設計思想,昇華自己高內聚和低耦合的理解,把自己變成一個更高level的software engineer;

  2. 通過做驅動,進一步理解Linux本身的程序、記憶體、IO等知識,昇華對軟體系統和效能分析的理解,把自己變成一個更高level的技術expert。

如果做了5年驅動,進入的時候是除錯暫存器搞示波器,出來的時候還是調暫存器搞示波器,那自然是完全沒有什麼前途的!

有沒有前途,這個事情,完全是因人而異的。前途是無所謂有,無所謂無的。你如果有抽象、衍生的能力和不斷學習總結的精神,無論是做驅動還是不做驅動,都會是很有前途的事情。反之,做什麼基本都沒前途。

更多精彩更新中……歡迎關注微信公眾號:linux閱碼場(id: linuxd