|
引言
計(jì)算機(jī)科學(xué)是一門應(yīng)用科學(xué),它的知識(shí)體系是典型的倒三角結(jié)構(gòu),所用的基礎(chǔ)知識(shí)并不多,只是隨著應(yīng)用領(lǐng)域和方向的不同,產(chǎn)生了很多的分支,所以說編程并不是一件很困難的事情,一個(gè)高中生經(jīng)過特定的訓(xùn)練就可以做得到。但是,會(huì)編程和編好程絕對(duì)是兩碼事,同樣的程序員,有的人幾年之后成為了架構(gòu)師,有的人卻還在不停地coding,只不過ctrl-c、ctrl-v用得更加純熟了。在中國,編程人員最終的歸途無外乎兩條:一是轉(zhuǎn)向技術(shù)管理,它的終點(diǎn)是CTO;二是繼續(xù)深入,它的終點(diǎn)是首席架構(gòu)師,成為CEO的人畢竟是少數(shù)。如果你現(xiàn)在還是個(gè)普通的程序員,希望繼續(xù)在技術(shù)這條路上前進(jìn)的話,我想你還是應(yīng)該先補(bǔ)充一點(diǎn)軟件工程的思想,學(xué)習(xí)一點(diǎn)有關(guān)設(shè)計(jì)模式的知識(shí),只有具備這些能力,你才能從整體和宏觀層面來考慮問題、分析問題和解決問題。本人Coding了很多年,中間走了不少彎路,雖然最終沒什么大成就,但總算有一些心得,很愿意把自己的一些經(jīng)驗(yàn)?zāi)贸鰜砀蠹曳窒恚@或許對(duì)你的發(fā)展有所幫助。
由程序員轉(zhuǎn)為架構(gòu)師,最繞不開的概念就算是面向?qū)ο?OO)了。記得在大學(xué)的時(shí)候,我們專業(yè)開了一門課叫《面向?qū)ο蟮木幊獭贰D莻€(gè)時(shí)候,我們剛剛學(xué)了一門C語言,開發(fā)環(huán)境用的還是DOS下的Turbo C,半點(diǎn)項(xiàng)目開發(fā)的經(jīng)驗(yàn)都沒有,純粹的空對(duì)空。所以,一學(xué)期下來,我始終處于一種懵懂狀態(tài),既沒領(lǐng)會(huì)面向過程和面向?qū)ο蟮降子惺裁磪^(qū)別,也沒搞懂面向?qū)ο竽軒硎裁春锰帯?/p>
面向過程(OP)和面向?qū)ο?OO)
1 蛋炒飯和蓋澆飯
有人這么形容OP和OO的不同:用面向過程的方法寫出來的程序是一份蛋炒飯,而用面向?qū)ο髮懗鰜淼某绦蚴且环萆w澆飯。所謂蓋澆飯,北京叫蓋飯,東北叫燴飯,廣東叫碟頭飯,就是在一碗白米飯上面澆上一份蓋菜,你喜歡什么菜,你就澆上什么菜。我覺得這個(gè)比喻還是比較貼切的。
蛋炒飯制作的細(xì)節(jié),我不太清楚,因?yàn)槲覜]當(dāng)過廚師,也不會(huì)做飯,但最后的一道工序肯定是把米飯和雞蛋混在一起炒勻。蓋澆飯呢,則是把米飯和蓋菜分別做好,你如果要一份紅燒肉蓋飯呢,就給你澆一份紅燒肉;如果要一份青椒土豆蓋澆飯,就給澆一份青椒土豆絲。
蛋炒飯的好處就是入味均勻,吃起來香。如果恰巧你不愛吃雞蛋,只愛吃青菜的話,那么唯一的辦法就是全部倒掉,重新做一份青菜炒飯了。蓋澆飯就沒這么多麻煩,你只需要把上面的蓋菜撥掉,更換一份蓋菜就可以了。蓋澆飯的缺點(diǎn)是入味不均,可能沒有蛋炒飯那么香。
到底是蛋炒飯好還是蓋澆飯好呢?其實(shí)這類問題都很難回答,非要比個(gè)上下高低的話,就必須設(shè)定一個(gè)場景,否則只能說是各有所長。如果大家都不是美食家,沒那么多講究,那么從飯館角度來講的話,做蓋澆飯顯然比蛋炒飯更有優(yōu)勢(shì),他可以組合出來任意多的組合,而且不會(huì)浪費(fèi)。
軟件工程
蓋澆飯的好處就是“菜”“飯”分離,從而提高了制作蓋澆飯的靈活性。飯不滿意就換飯,菜不滿意換菜。用軟件工程的專業(yè)術(shù)語就是“可維護(hù)性”比較好,“飯”和“菜”的耦合度比較低。蛋炒飯將“蛋”“飯”攪和在一起,想換“蛋”“飯”中任何一種都很困難,耦合度很高,以至于“可維護(hù)性”比較差。軟件工程追求的目標(biāo)之一就是可維護(hù)性,可維護(hù)性主要表現(xiàn)在3個(gè)方面:可理解性、可測試性和可修改性。面向?qū)ο蟮闹饕锰幘褪秋@著的改善了軟件的可維護(hù)性。
面向過程(OP)和面向?qū)ο?OO)是不是就是指編碼的兩種方式呢?不是!你拿到了一個(gè)用戶需求,比如有人要找你編個(gè)軟件,你是不是需要經(jīng)過需求分析,然后進(jìn)行總體/詳細(xì)設(shè)計(jì),最后編碼,才能最終寫出軟件,交付給用戶。這個(gè)過程是符合人類基本行為方式的:先想做什么,再想如何去做,最后才是做事情。有的同學(xué)說:“我沒按照你說的步驟做啊,我是直接編碼的”。其實(shí),你一定會(huì)經(jīng)歷了這三個(gè)階段,只不過你潛意識(shí)里沒有分得那么清楚。對(duì)于拿到需求就編碼的人,可能編著編著,又得倒回去重新琢磨,還是免不了這些過程,
以O(shè)O為例,對(duì)應(yīng)于軟件開發(fā)的過程,OO衍生出3個(gè)概念:OOA、OOD和OOP。采用面向?qū)ο筮M(jìn)行分析的方式稱為OOA,采用面向?qū)ο筮M(jìn)行設(shè)計(jì)的方式稱為OOD,采用面向?qū)ο筮M(jìn)行編碼的方式稱為OOP。面向過程(OP)和面向?qū)ο?OO)本質(zhì)的區(qū)別在于分析方式的不同,最終導(dǎo)致了編碼方式的不同。
面向過程編程(OPP) 和面向?qū)ο缶幊?OOP)的關(guān)系
關(guān)于面向過程的編程(OPP)和面向?qū)ο蟮木幊?OOP),給出這它們的定義的人很多,您可以從任何資料中找到很專業(yè)的解釋,但以我的經(jīng)驗(yàn)來看,講的相對(duì)枯燥一點(diǎn),不是很直觀。除非您已經(jīng)有了相當(dāng)?shù)姆e累,否則說起來還是比較費(fèi)勁。
我是個(gè)老程序員出身,雖然現(xiàn)在的日常工作更多傾向了管理,但至今依然保持編碼的習(xí)慣,這句話什么意思呢?我跟大家溝通應(yīng)該沒有問題。無論你是在重復(fù)我走過的路,或者已經(jīng)走在了我的前面,大家都會(huì)有那么一段相同的經(jīng)歷,都會(huì)在思想層面上有一種理解和默契,所以我還是會(huì)盡量按照大多數(shù)人的常規(guī)思維寫下去。
面向過程的編程(OPP)產(chǎn)生在前,面向?qū)ο蟮木幊?OOP)產(chǎn)生在后,所以面向?qū)ο蟮木幊?OOP)一定會(huì)繼承前者的一些優(yōu)點(diǎn),并摒棄前者存在的一些缺點(diǎn),這是符合人類進(jìn)步的自然規(guī)律。兩者在各自的發(fā)展和演變過程中,也一定會(huì)相互借鑒,互相融合,來吸收對(duì)方優(yōu)點(diǎn),從而出現(xiàn)在某些方面的趨同性,這些是必然的結(jié)果。即使兩者有更多的相似點(diǎn),也不會(huì)改變它們本質(zhì)上的不同,因?yàn)樗鼈兊某霭l(fā)點(diǎn)就完全是兩種截然不同的思維方式。關(guān)于兩者的關(guān)系,我的觀點(diǎn)是這樣的:面向?qū)ο缶幊?OOP)在局部上一定是面向過程(OP)的,面向過程的編程(OPP)在整體上應(yīng)該借鑒面向?qū)ο?OO)的思想。這一段說的的確很空洞,而且也一定會(huì)有引來爭議,不過,我勸您還是在閱讀了后面的內(nèi)容之后,再來評(píng)判我觀點(diǎn)的正確與否。
象C++、C#、Java等都是面向?qū)ο蟮恼Z言,c,php(暫且這么說,因?yàn)?a href=/itjie/phpjishu/ target=_blank class=infotextkey>php4以后就支持OO)都是面向過程的語言,那么是不是我用C++寫的程序一定就是面向?qū)ο螅胏寫的程序一定就是面向過程呢?這種觀點(diǎn)顯然是沒有真正吃透兩者的區(qū)別。語言永遠(yuǎn)是一種工具,前輩們每創(chuàng)造出來的一種語言,都是你用來實(shí)現(xiàn)想法的利器。我覺得好多人用C#,Java寫出來的代碼,要是仔細(xì)看看,那實(shí)際就是用面向?qū)ο?OO)的語言寫的面向過程(OP)的程序。
所以,即使給關(guān)羽一根木棍,給你一桿青龍偃月刀,他照樣可以打得你滿頭是包。你就是扛著個(gè)偃月刀,也成不了關(guān)羽,因?yàn)槟闳狈﹃P(guān)羽最本質(zhì)的東西---絕世武功。同樣的道理,如果你沒有領(lǐng)會(huì)OO思想,怎么可能寫得出真正的OO程序呢?面向?qū)ο?OO)和面向過程(OP)絕對(duì)是兩種截然不同的思維方式。
那是不是面向過程就不好,也沒有存在的必要了?我從來沒有這樣說過。事實(shí)上,面向過程的編程(OPP)已經(jīng)存在了幾十年了,現(xiàn)在依然有很多人在使用。它的優(yōu)點(diǎn)就是邏輯不復(fù)雜的情況下很容易理解,而且運(yùn)行效率遠(yuǎn)高于面向?qū)ο螅∣O)編寫的程序。所以,系統(tǒng)級(jí)的應(yīng)用或準(zhǔn)實(shí)時(shí)系統(tǒng)中,依然采用面向過程的編程(OPP)。當(dāng)然,很多編程高手以及大師級(jí)的人物,他們由于對(duì)于系統(tǒng)整體的掌控能力很強(qiáng),也喜歡使用面向過程的編程(OPP),比如像Apache,QMail,PostFix,ICE等等這些比較經(jīng)典的系統(tǒng)都是OPP的產(chǎn)物。
象php這些腳本語言,主要用于web開發(fā),對(duì)于一些業(yè)務(wù)邏輯相對(duì)簡單的系統(tǒng),也常使用面向過程的編程(OPP),這也是php無法跨入到企業(yè)級(jí)應(yīng)用開發(fā)的原因之一,不過php5目前已經(jīng)能夠很好的支持OO了。
詳解面向過程的編程(OPP)
在面向?qū)ο蟪霈F(xiàn)之前,我們采用的開發(fā)方法都是面向過程的編程(OPP)。面向過程的編程中最常用的一個(gè)分析方法是“功能分解”。我們會(huì)把用戶需求先分解成模塊,然后把模塊分解成大的功能,再把大的功能分解成小的功能,整個(gè)需求就是按照這樣的方式,最終分解成一個(gè)一個(gè)的函數(shù)。這種解決問題的方式稱為“自頂向下”,原則是“先整體后局部”,“先大后小”,也有人喜歡使用“自下向上”的分析方式,先解決局部難點(diǎn),逐步擴(kuò)大開來,最后組合出來整個(gè)程序。其實(shí),這兩種方式殊路同歸,最終都能解決問題,但一般情況下采用“自頂向下”的方式還是較為常見,因?yàn)檫@種方式最容易看清問題的本質(zhì)。
我舉個(gè)例子來說明面向過程的編程方式:
用戶需求:老板讓我寫個(gè)通用計(jì)算器。
最終用戶就是老板,我作為程序員,任務(wù)就是寫一個(gè)計(jì)算器程序。OK,很簡單,以下就是用C語言完成的計(jì)算器:
假定程序的文件名為:main.c。
int main(int argc, char *argv[]){
//變量初始化
int nNum1,nNum2;
char cOpr;
int nResult;
nNum1 = nNum2 = 0;
cOpr = 0;
nResult = 0;
//輸入數(shù)據(jù)
printf("Please input the first number:/r/n");
scanf("%d",&nNum1);
printf("Please input the operator:/r/n");
scanf("%s",&cOpr);
printf("Please input the second number:/r/n");
scanf("%d",&nNum2);
//計(jì)算結(jié)果
if( cOpr == '+' ){
nResult = nNum1 + nNum2;
}else if( cOpr == '-' ){
nResult = nNum1 - nNum2;
}else{
printf("Unknown operator!");
return -1;
}
//輸出結(jié)果
printf("The result is %d!",nResult);
return 0;
}
it知識(shí)庫:如何從普通程序員晉升為架構(gòu)師,轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。