自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

有關(guān)C語言模塊化實(shí)現(xiàn)的探討

開發(fā) 架構(gòu) 后端
怎樣才是好的設(shè)計(jì)?模塊化是我們經(jīng)常談?wù)摰囊粋€(gè)方向,它將復(fù)雜的問題分解成小問題,實(shí)現(xiàn)高內(nèi)聚,低耦合。不過,模塊之間的聯(lián)系需要遵循的原則,堅(jiān)持起來是很難的。本文探討了C語言實(shí)現(xiàn)模塊化的一些問題。

本文節(jié)選自云風(fēng)的博客上近日的兩篇文章:《好的設(shè)計(jì)》和《C 語言對(duì)模塊化支持的欠缺》。

由于最近幾年用的主要開發(fā)語言是 C 和 lua 。那么也打算以此為基礎(chǔ)寫。假定讀者至少有不錯(cuò)的 C 語言基礎(chǔ)了。我真正想談的是,如何把一個(gè)軟件很好的構(gòu)建起來。到底需要做些什么。(從實(shí)現(xiàn)層面看)怎樣才是好的軟件。

那么有一個(gè)重點(diǎn)問題,也是老問題,怎樣才是好的設(shè)計(jì)。

好的設(shè)計(jì),必然是容易實(shí)現(xiàn)的。它可以很精巧,但不能難以理解。

太陽底下無新鮮事。軟件行業(yè)已經(jīng)發(fā)展了這么多年,你想到的東西,肯定有人都想到過了。

每個(gè)軟件也都有它的生命期,我們只要在它的生命期內(nèi)完成它的使命就行了。軟件往往需要盡快的投入使用,然后在使用中演化。這個(gè)演化最大可能并不依靠你一個(gè)人的力量去推動(dòng)。隨著參與的人增加,人和人(指開發(fā)人員)的共性就會(huì)減少。每個(gè)人都看得懂可以充分接受,軟件才不容易向壞的方面演化。

我們常常談模塊化,談高內(nèi)聚,低耦合。

本質(zhì)上,就是如何管理復(fù)雜度。如何把一件很難的事情(開發(fā)一個(gè)軟件),分解成小問題,分而治之。

這些小問題之間的千絲萬縷的聯(lián)系,是設(shè)計(jì)人員面臨的最大難題。

有些原則聽起來不錯(cuò),但是堅(jiān)持起來很難。

比如,讓模塊的輸入輸出沒有副作用。你能讓你的模塊每個(gè)輸入對(duì)對(duì)應(yīng)著唯一輸出嗎?

又比如,讓模塊層次化。如果 A 模塊依賴 B 模塊,B 模塊依賴 C 模塊。一旦出現(xiàn)這個(gè)狀態(tài),你能保證 A 模塊絕對(duì)和 C 模塊隔絕嗎?更有甚者,讓三個(gè)模塊循環(huán)依賴這種更糟糕的事情也并不鮮見。

抽象是個(gè)好東西。但借助不斷的抽象,問題不斷的包起來,演化成新的巨無霸,顯然會(huì)讓事情更糟。雖然最終可能真的能像搭積木一樣去組裝軟件了?;蚴枪蛡蚋嗟某绦騿T填表單一樣的工作,相互不需要對(duì)方在做什么。但是,軟件性能卻下降到了不可以忍受的地步。bug 也隱藏的更久,更不可收拾。

好的設(shè)計(jì),必須對(duì)問題有足夠清晰的理解。有如庖丁解牛一般,把整個(gè)問題劃開,在最薄弱的地方分離。其實(shí),做到這點(diǎn),也就夠了。

解決這些問題,其實(shí)跟語言無關(guān)。語言之爭是沒有多大意義的。如開頭所說,把設(shè)計(jì)做好,模塊之間的關(guān)系,用足夠簡單的方式就能描述清楚了,大部分流行的開發(fā)語言都能做到。

用 C 來實(shí)作,而沒有用它的近親 C++ ,也是為了避免狹隘的爭議:我們?cè)撚眠@個(gè)特性嗎?該用那個(gè)特性嗎?這個(gè)形式做是不是好點(diǎn)?那樣會(huì)不會(huì)有更好的性能?

所謂開發(fā)效率,對(duì)于個(gè)人來說,語言之不同,是會(huì)有很大差異。但是那是實(shí)現(xiàn)層面的差異。對(duì)于完成設(shè)計(jì),這個(gè)過程,效率和所用語言無關(guān)。

實(shí)現(xiàn)的階段,程序員可不可以開心的放心的去完成那些接口,這就是衡量設(shè)計(jì)好不好的指標(biāo)了。這個(gè)時(shí)候,一個(gè)高開發(fā)效率的語言有優(yōu)勢(shì)(更少的代碼量),一個(gè)容易掌握的語言也有優(yōu)勢(shì)(可以讓更多的人參于而少犯錯(cuò)誤)。

#t#對(duì)于我的團(tuán)隊(duì),我會(huì)更樂于采用一種讓實(shí)現(xiàn)人員更輕松的方式。不用理會(huì)太多的語言細(xì)節(jié),不用在投入開發(fā)前學(xué)習(xí)更多的概念(尤其是這個(gè)項(xiàng)目獨(dú)有的),不用特別嚴(yán)格的 code review 也可以允許大家提交新的代碼,切不至于輕易的引入 bug 。

我相信,軟件做到后面,設(shè)計(jì)人員不需要親自寫太多代碼。雖然我現(xiàn)在每天還是大量的寫,也并不覺得枯燥。

事必恭親是不好,但并不是說,你給實(shí)現(xiàn)人員足夠信任就可以放手的。真正讓你放手的只能是,你做出了好的設(shè)計(jì),無論是誰,他也寫不壞它。這時(shí),是你樂意自己寫,還是多找?guī)讉€(gè)同學(xué)幫忙寫,已經(jīng)不重要了。

#p#

那么我們來討論一下怎樣構(gòu)建一個(gè)(稍具規(guī)模的)軟件。我選擇用 C 為實(shí)現(xiàn)工具來做這件事情。就不得不談?wù)Z言還沒有提供給我們的東西。

模塊化是最高原則之一(在 《Unix 編程藝術(shù)》一書中, Unix 哲學(xué)第一條即:模塊原則),我們就當(dāng)考慮如何簡潔明快的使用 C 語言實(shí)現(xiàn)模塊化。

除開 C/C++ ,在其它現(xiàn)在流行的開發(fā)語言中,缺少標(biāo)準(zhǔn)化的模塊管理機(jī)制是很難想象的。但這也是 C 語言本身的設(shè)計(jì)哲學(xué)決定的:把盡可能多的可能性留給程序員。根據(jù)實(shí)際的系統(tǒng),實(shí)際的需要去定制自己需要的東西。

對(duì)于巨型的系統(tǒng)(比如 Windows 這樣的操作系統(tǒng)),一般會(huì)考慮使用一種二進(jìn)制級(jí)的模塊化方案。由模塊自己提供元信息,或是使用統(tǒng)一的管理方案(比如注冊(cè)表)。稍小一點(diǎn)的系統(tǒng)(我們通常開發(fā)接觸到的),則會(huì)考慮輕量一些的源碼級(jí)方案。

首先要考慮的往往是模塊的依賴關(guān)系和初始化過程。

依賴關(guān)系可以放由鏈接器或加載器來解決。尤其在使用 C 語言時(shí),簡單的靜態(tài)庫或動(dòng)態(tài)庫,都不太會(huì)引起大的麻煩。

C++ 則不然,C++ 的某些特性(比如模板類靜態(tài)成員的構(gòu)造)必須對(duì)早期只供 C 語言使用的鏈接器做一些增強(qiáng)。即使是精心編寫的 C++ 庫,也有可能出現(xiàn)一些意外的 bug 。這些 bug 往往需要對(duì)編譯,鏈接,加載過程很深刻的理解,才能查出來。注:我并不想以此來反對(duì)使用 C++ 做開發(fā)。

我們需要著重管理的,是模塊的初始化過程。

對(duì)于打包在一起的一個(gè)庫(例如 glibc ,或是 msvcrt ),會(huì)在加載時(shí)有初始化入口,以及卸載時(shí)有結(jié)束代碼。我想說的不是這個(gè),而是我們自己內(nèi)部拆分的更小的模塊的相互依賴關(guān)系。

誰先初始化,誰后初始化,這是一個(gè)問題。

在 C++ 的語言級(jí)解決方案中,使用的是單件模塊。要么由鏈接器決定以怎樣的次序來生成初始化代碼,這,通常會(huì)因?yàn)橐蕾囮P(guān)系和實(shí)際構(gòu)造次序不同而導(dǎo)致 bug (注:我在某幾本 C++ 書中都見過,待核實(shí)。自己好久不寫 C++ 也沒有實(shí)際的錯(cuò)誤例子);要么使用惰性初始化方案。這個(gè)惰性初始化也不是萬能的,并且有些額外的開銷。(多線程環(huán)境中尤其需要注意)

我使用 C 語言做初期設(shè)計(jì)的時(shí)候,采用的是一種足夠簡單的方法。就是,以編碼規(guī)范來規(guī)定,每個(gè)模塊必須存在一個(gè)初始化函數(shù),有規(guī)范的名字。比如 foo 模塊的初始化入口叫

  1. int foo_init()  
  2.  

#t#規(guī)定:凡使用特定模塊,必須調(diào)用模塊初始化函數(shù)。

為了避免模塊重復(fù)初始化,初始化函數(shù)并不直接調(diào)用,而是間接的。類似這樣: mod_using(foo_init);

mod_using 負(fù)責(zé)調(diào)用初始化函數(shù),并保證不重復(fù)調(diào)用,也可以檢查循環(huán)依賴。

在這里,我們還約定了初始化成功于否的返回值。(在我們的系統(tǒng)中,返回 0 表示正確,1 表示失?。┤缓蠖x了一個(gè)宏來做這個(gè)使用。

  1. #define USING(m) if (mod_using(m##_init,#m)) { return 1; }  
  2.  

注:我個(gè)人反對(duì)濫用宏。也盡可能的避免它。這里使用宏,經(jīng)過了慎重的考慮。我希望可以有一個(gè)代碼掃描器去判斷我是否漏掉了模塊初始化(可能我使用了一個(gè)模塊,但忘記初始化它)。宏可以幫助代碼掃描分析器更容易實(shí)現(xiàn)。而且,使用宏更像是對(duì)語言做的輕微且必要的擴(kuò)展。

這樣,我的系統(tǒng)中模塊模塊的實(shí)現(xiàn)代碼最后,都有一個(gè) init 函數(shù),里面只是簡單的調(diào)用了 USING 來引用別的模塊。例如:

  1. #include "module.h"  
  2.  
  3. /*  
  4.   我個(gè)人偏愛把 module.h 的引入放在源文件最后,初始化入口之前。  
  5.   它里面之定義了 USING 宏,以及相關(guān)管理函數(shù)。  
  6.   這樣做是為了避免在代碼的其它地方去引入別的模塊。  
  7. */ 
  8.  
  9. int 
  10. foo_init()  
  11. {  
  12.   USING(memory);  // 引用內(nèi)存管理模塊  
  13.   USING(log);  // 引用 log 模塊  
  14.  
  15.   return 0;  
  16. }  
  17.  

至于模塊的卸載,大部分需求下是不需要的。今天在這里就不論證這一點(diǎn)了。

責(zé)任編輯:yangsai 來源: 云風(fēng)的Blog
相關(guān)推薦

2011-05-13 15:54:50

C模塊化

2011-05-13 15:46:49

C模塊化

2024-07-01 12:48:00

C++內(nèi)部類開發(fā)

2022-09-21 11:51:26

模塊化應(yīng)用

2016-12-14 14:50:26

CSS預(yù)處理語言模塊化實(shí)踐

2019-08-28 16:18:39

JavaScriptJS前端

2020-09-17 10:30:21

前端模塊化組件

2020-09-18 09:02:32

前端模塊化

2010-01-21 09:27:30

模塊化的優(yōu)點(diǎn)NetBeans

2021-04-06 10:19:36

Go語言基礎(chǔ)技術(shù)

2009-08-17 10:11:12

C# Windows

2010-03-11 17:24:27

Python編程語言

2022-09-05 09:01:13

前端模塊化

2023-12-25 22:24:36

C++模塊Module

2016-10-09 11:03:41

Javascript模塊化Web

2013-08-20 15:31:18

前端模塊化

2017-05-18 10:23:55

模塊化開發(fā)RequireJsJavascript

2015-10-10 11:29:45

Java模塊化系統(tǒng)初探

2022-03-11 13:01:27

前端模塊

2010-05-28 10:31:28

模塊化IT
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)