作者: GorgonMeducer 傻孩子
首發(fā):裸機(jī)思維
【說在前面的話】
在前面一篇文章《真刀真槍模塊化(1)——一本糊涂賬》中,我們討論了:
在工程開發(fā)中進(jìn)行模塊化的本來目的——為了復(fù)用已有的代碼,節(jié)省當(dāng)前項(xiàng)目的開發(fā)時(shí)間;
實(shí)際操作過程中遇到的尷尬問題——模塊的具體實(shí)現(xiàn)原本應(yīng)該被視作黑盒子,程序員因?yàn)楦鞣N心理上的原因要閱讀代碼;
以及
“原則上”的解決方案——嚴(yán)禁程序員在項(xiàng)目開發(fā)過程中閱讀模塊的具體實(shí)現(xiàn)代碼。
道理說起來簡(jiǎn)單,真要實(shí)際操作起來,一線開發(fā)人員往往會(huì)直搖頭:手中已有的所謂“模塊”質(zhì)量參差不齊、模塊的開發(fā)者魚龍混雜、很多模塊別說出了問題要找開發(fā)方負(fù)責(zé)維護(hù)了,就是原作者是誰恐怕都找不到了——在這種情況下,大談“禁止開發(fā)人員閱讀模塊的實(shí)現(xiàn)代碼”,簡(jiǎn)直就是天方夜譚,頗有幾分“何不食肉糜”的傲慢。
——難道模塊化本身錯(cuò)了么?實(shí)際情況并非如此,這里傻孩子忍不住想“感慨”兩句:在追求和實(shí)踐新的方法(論)的時(shí)候,總難免會(huì)遇到這樣那樣的困難,有的困難甚至讓整個(gè)方案看起來“完全行不通”——在這種時(shí)候,如果立即退出來將整個(gè)方法全盤否定,就會(huì)失去寶貴的前進(jìn)機(jī)會(huì)。
在模塊化的過程中,要想發(fā)揮模塊化“復(fù)用已有代碼”、“降低開發(fā)時(shí)間”的作用,就必須將模塊視作黑盒子;一旦模塊被視作黑盒子,實(shí)現(xiàn)的質(zhì)量和后續(xù)的可靠維護(hù)就成為當(dāng)前模塊是否可用的基石——進(jìn)一步來說,不靠譜的代碼實(shí)現(xiàn)和差強(qiáng)人意的接口設(shè)計(jì)與封裝是導(dǎo)致模塊化失敗的根本原因。
本文將為您介紹一種模塊化封裝的簡(jiǎn)單操作方式——由傻孩子根據(jù)十多年工程實(shí)踐經(jīng)驗(yàn)總結(jié)、歷經(jīng)無數(shù)商業(yè)項(xiàng)目的千錘百煉。通過這一方式構(gòu)建的模塊,我稱之為服務(wù)(Service),因此,這里所要介紹的模型又被稱之為“Service模型”。
【正文】
從具體操作層面來說,所謂Service模型并不復(fù)雜。
首先,每一個(gè)模塊都有一個(gè)屬于自己的專門的文件夾,文件夾的名稱與模塊名相同:
其次,每一個(gè)模塊中都有一個(gè)專門的頭文件,用于提供給模塊的使用者來包含(#include);該頭文件的名稱必須與模塊的名稱相同。
需要特別強(qiáng)調(diào)和說明的是:
該頭文件用于“從模塊內(nèi)部向模塊外部”提供使用模塊所必須的“最小信息”;
任何人要使用模塊,必須且只能包含該頭文件;
我們把這類向模塊的使用者提供必要信息的頭文件稱之為接口頭文件;
接口頭文件遵循“最小信息公開原則”,即,該頭文件中只存放用戶使用模塊最少最少所必須知道的信息。實(shí)際操作中,類型定義、宏定義、函數(shù)和全局變量聲明都應(yīng)該首先放置在對(duì)應(yīng)的源代碼中(或是后面會(huì)提到的模塊內(nèi)私有的接口頭文件中);當(dāng)且僅當(dāng)我們發(fā)現(xiàn)用戶要使用模塊的某一功能必須要用到某一信息時(shí),才“極不情愿”地、“摳門”的、且盡可能將其它能剝離和隱藏的信息剝離開后,放置到接口頭文件中。
與接口頭文件相對(duì),每一個(gè)模塊內(nèi)部都會(huì)有一個(gè)專門的頭文件用于實(shí)現(xiàn)對(duì)模塊的配置:
該頭文件用于“從模塊外部向模塊內(nèi)部”輸入配置信息;
如無特殊說明或安排,該頭文件應(yīng)該固定命名為 app/_cfg.h(沒有額外的前綴和后綴);
如無特殊說明或安排,該頭文件應(yīng)該僅包含配置信息,例如:宏定義、類型定義(在極其特殊的情況下,偶爾出現(xiàn)的全局變量或者函數(shù)聲明);
我們把這類頭文件稱之為“配置頭文件”;
在構(gòu)建和使用模塊的時(shí)候,無論是模塊的設(shè)計(jì)者還是模塊的使用者,都應(yīng)該遵循黑盒子原則,在操作上表現(xiàn)為——模塊的使用者不應(yīng)該修改任何位于模塊文件夾內(nèi)部的內(nèi)容——模塊文件夾既是黑盒子的容器,也是黑盒子的邊界。
為了遵守這一原則,模塊內(nèi)部的配置頭文件實(shí)際上是不允許用戶去修改的——那么這又如何讓用戶更改對(duì)模塊的各個(gè)配置選項(xiàng)呢?答案很簡(jiǎn)單,如下圖所示:模塊內(nèi)部的app/_cfg.h 在文件的一開始會(huì)首先包含上一級(jí)目錄的app/_cfg.h。
為了實(shí)現(xiàn)這一點(diǎn),一個(gè)模塊內(nèi)部 app/_cfg.h 的固定內(nèi)容格式為:
//!作為模塊的用戶,不要修改這里的任何內(nèi)容
一個(gè)模塊的接口頭文件,其內(nèi)部格式可能為:
//!作為模塊的用戶,不要修改這里的任何內(nèi)容
可以很容易注意到,當(dāng)使用某一模塊時(shí),用戶可以很方便的在模塊外部定義一個(gè)屬于自己的 app/_cfg.h 來向模塊提供配置信息——而無論如何修改這一文件,都不會(huì)破壞黑盒子本身的內(nèi)容。
再次,一個(gè)模塊往往擁有一個(gè)或多個(gè)C源文件,它只需要包含模塊的接口頭文件,就可以共享一些“對(duì)外公開的信息”。
這里有個(gè)朋友會(huì)問了:根據(jù)最小信息公開原則,接口頭文件中只包含了一些最小信息,如果模塊內(nèi)的多個(gè)C源文件之間需要共享一些非公開的私有信息,該怎么處理呢?
為了解決這一問題,我們一般會(huì)引入一個(gè)以雙下劃線為前綴的接口頭文件(比如,叫做/_/_common.h),并視其為模塊的私有財(cái)產(chǎn)。如下圖所示,這一頭文件是僅供模塊內(nèi)的源代碼包含的——無論是模塊的接口頭文件還是模塊的配置頭文件都不應(yīng)該對(duì)其進(jìn)行包含——以防信息泄露:
一個(gè)典型的 /_/_common.h 內(nèi)容如下:
/*!作為模塊的用戶,不要修改這里的任何內(nèi)容,理論上也不應(yīng)該關(guān)心這
基于這一規(guī)則,模塊內(nèi)一個(gè)可能的C源文件內(nèi)容如下:
//! 作為模塊的用戶,不要修改這里的任何內(nèi)容
最后,一個(gè)模塊內(nèi)是允許包含其它子模塊的,對(duì)于這種嵌套情況,僅需要兩步驟就可以完成部署:
將子模塊拷貝到父模塊中,或者按照前述的模塊構(gòu)建規(guī)則,在父模塊中建立一個(gè)子模塊;
父模塊的接口頭文件包含子模塊的接口頭文件
少數(shù)情況下,如果子模塊與父模塊高度耦合(一般來說就是在父模塊中從頭開始建立一個(gè)新的子模塊時(shí)會(huì)發(fā)生這種情況)——比如子模塊依賴父模塊的 /_/_common.h 中提供的信息,則應(yīng)該在子模塊中也建立一個(gè) /_/_common.h,并仿照 app/_cfg.h 的做法,在頭文件的一開始首先向上包含父模塊的 /_/_common.h;
如果父模塊包含/_/_common.h,而子模塊并不需要這一信息,則子模塊無需在做任何特殊修改。
對(duì)app/_cfg.h來說,由于子模塊原本就會(huì)自動(dòng)包含上一級(jí)的app/_cfg.h,因此,我們無須做任何特殊操作,子模塊就可以透過父模塊的app/_cfg.h自動(dòng)從外界獲取配置信息——這就像是一種標(biāo)準(zhǔn)化的水管安裝。
以上就是使用Service模型進(jìn)行模塊化的基本規(guī)則。是不是很簡(jiǎn)單?
【后記】
Service模型本身是完全本著簡(jiǎn)化用戶操作的宗旨,以實(shí)用性為重中之重,同時(shí)也避免一切“反直覺”的設(shè)定。
對(duì)用戶來說,這一模型是非常友好的:
只需要拷貝模塊目錄就可以完成部署;
只需要在模塊的外部額外添加一個(gè)app/_cfg.h就可以實(shí)現(xiàn)對(duì)模塊的配置;
所有關(guān)于模塊的使用信息(使用說明書)都放置在一個(gè)唯一的、與模塊同名的接口頭文件中;且這里包含的信息對(duì)用戶來說都是可用的(沒有無用信息,也沒有多余信息);
對(duì)模塊的開發(fā)者來說:
這一模型是高度遵守黑盒子原則的;
用戶使用模塊,是不需要“用臟手染指”自己寶貴的代碼的(無需修改);
對(duì)制作 Library 非常友好,只需要保留接口頭文件,而將其它所有文件(包括源代碼和私有接口頭文件)刪除并保留一個(gè)固化好的app/_cfg.h即可。
模塊是非常容易遷移和嵌套的。
當(dāng)然,這一Service模型也有一個(gè)小缺點(diǎn)(可能有些人也對(duì)此無法容忍),即,用某些工程管理工具將頭文件的包含關(guān)系展開時(shí),通常會(huì)看到海量的app/_cfg.h(盡管他們內(nèi)部都使用了模塊特有的保護(hù)宏進(jìn)行區(qū)別)——對(duì)于這一問題,在真刀真槍模塊化的后續(xù)內(nèi)容中,將提供一個(gè)較為完美的解決方案,這里就先賣個(gè)關(guān)子——對(duì)普通用戶來說,現(xiàn)有的Service模型足夠了。
審核編輯 黃昊宇
-
模型
+關(guān)注
關(guān)注
1文章
3464瀏覽量
49803 -
Service
+關(guān)注
關(guān)注
0文章
30瀏覽量
13991
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
MCU-40型自動(dòng)測(cè)量是如何實(shí)現(xiàn)分布式模塊化?

MCU分布式模塊化自動(dòng)測(cè)量單元:數(shù)據(jù)傳輸與處理能力如何?

重磅新品|CMW系列模塊化連接器

原理圖模塊化,BOM 物料位號(hào)處理
華為預(yù)制模塊化數(shù)據(jù)中心連續(xù)十年蟬聯(lián)全球第一
全球第四 科華數(shù)據(jù)蟬聯(lián)全球模塊化UPS榜單

模塊化示波器的技術(shù)原理和應(yīng)用
模塊化儀器的技術(shù)原理和應(yīng)用場(chǎng)景
銘普推出創(chuàng)新模塊化儲(chǔ)能系統(tǒng)
即插即用DAQ設(shè)備與模塊化DAQ系統(tǒng)的概念解析

模塊化插座接線方法有哪些
通信設(shè)備安全引發(fā)全球關(guān)注!國(guó)產(chǎn)化替代迫在眉睫

研華工控機(jī)的模塊化設(shè)計(jì),復(fù)雜應(yīng)用場(chǎng)景的靈活解決方案!

耐世特推出模塊化小齒輪式電動(dòng)助力轉(zhuǎn)向系統(tǒng)
模塊化不間斷電源和傳統(tǒng)差距,安裝位置方面

評(píng)論