.NET 進階架構師0002 架構師之路(1)---面向過程和物件導向

來源:互聯網
上載者:User

標籤:等等   應用開發   軟體   發展   opp   領域   需要   實戰   調度   

1、引言
     機算機科學是一門應用科學,它的知識體系是典型的倒三角結構,所用的基礎知識並不多,只是隨著應用領域和方向的不同,產生了很多的分支,所以說編程並不是一件很困難的事情,一個高中生經過特定的訓練就可以做得到。但是,會編程和編好程絕對是兩碼事,同樣的程式員,有的人幾年之後成為了架構師,有的人卻還在不停地coding,只不過ctrl-c、ctrl-v用得更加純熟了。在中國,編程人員最終的歸途無外乎兩條:一是轉向技術管理,它的終點是CTO;二是繼續深入,它的終點是首席架構師,成為CEO的人畢竟是少數。如果你現在還是個普通的程式員,希望繼續在技術這條路上前進的話,我想你還是應該先補充一點軟體工程的思想,學習一點有關設計模式的知識,只有具備這些能力,你才能從整體和宏觀層面來考慮問題、分析問題和解決問題。本人Coding了很多年,中間走了不少彎路,雖然最終沒什麼大成就,但總算有一些心得,很願意把自己的一些經驗拿出來跟大家分享,這或許對你的發展有所協助。由程式員轉為架構師,最繞不開的概念就算是物件導向(OO)了。記得在大學的時候,我們專業開了一門課叫《物件導向的編程》。那個時候,我們剛剛學了一門C語言,開發環境用的還是DOS下的Turbo C,半點鐘項目開發的經驗都沒有,純粹的空對空。所以,一學期下來,我始終處於一種懵懂狀態,既沒領會面向過程和物件導向到底有什麼區別,也沒搞懂物件導向能帶來什麼好處。
2、面向過程(OP)和物件導向(OO) 
2.1 蛋炒飯和蓋澆飯
      有人這麼形容OP和OO的不同:用面向過程的方法寫出來的程式是一份蛋炒飯,而用物件導向寫出來的程式是一份蓋澆飯。所謂蓋澆飯,北京叫蓋飯,東北叫燴飯,廣東叫碟頭飯,就是在一碗白米飯上面澆上一份蓋菜,你喜歡什麼菜,你就澆上什麼菜。我覺得這個比喻還是比較貼切的。
蛋炒飯製作的細節,我不太清楚,因為我沒當過廚師,也不會做飯,但最後的一道工序肯定是把米飯和雞蛋混在一起炒勻。蓋澆飯呢,則是把米飯和蓋菜分別做好,你如果要一份紅燒肉蓋飯呢,就給你澆一份紅燒肉;如果要一份青椒馬鈴薯蓋澆飯,就給澆一份青椒馬鈴薯絲。
      蛋炒飯的好處就是入味均勻,吃起來香。如果恰巧你不愛吃雞蛋,只愛吃青菜的話,那麼唯一的辦法就是全部倒掉,重新做一份青菜炒飯了。蓋澆飯就沒這麼多麻煩,你只需要把上面的蓋菜撥掉,更換一份蓋菜就可以了。蓋澆飯的缺點是入味不均,可能沒有蛋炒飯那麼香。
到底是蛋炒飯好還是蓋澆飯好呢?其實這類問題都很難回答,非要比個上下高低的話,就必須設定一個情境,否則只能說是各有所長。如果大家都不是美食家,沒那麼多講究,那麼從飯館角度來講的話,做蓋澆飯顯然比蛋炒飯更有優勢,他可以組合出來任意多的組合,而且不會浪費。  2.2 軟體工程
      蓋澆飯的好處就是“菜”“飯”分離,從而提高了製作蓋澆飯的靈活性。飯不滿意就換飯,菜不滿意換菜。用軟體工程的專業術語就是“可維護性”比較好,“飯”和“菜”的耦合度比較低。蛋炒飯將“蛋”“飯”攪和在一起,想換“蛋”“飯”中任何一種都很困難,耦合度很高,以至於“可維護性”比較差。軟體工程追求的目標之一就是可維護性,可維護性主要表現在3個方面:可理解性、可測試性和可修改性。物件導向的主要好處就是顯著的改善了軟體的可維護性。
      面向過程(OP)和物件導向(OO)是不是就是指編碼的兩種方式呢?不是!你拿到了一個使用者需求,比如有人要找你編個軟體,你是不是需要經過需求分析,然後進行總體/詳細設計,最後編碼,才能最終寫出軟體,交付給使用者。這個過程是符合人類基本行為方式的:先想做什麼,再想如何去做,最後才是做事情。有的同學說:“我沒按照你說的步驟做啊,我是直接編碼的”。其實,你一定會經曆了這三個階段,只不過你潛意識裡沒有分得那麼清楚。對於拿到需求就編碼的人,可能編著編著,又得倒回去重新琢磨,還是免不了這些過程,
      以OO為例,對應於軟體開發的過程,OO衍生出3個概念:OOA、OOD和OOP。採用物件導向進行分析的方式稱為OOA,採用物件導向進行設計的方式稱為OOD,採用物件導向進行編碼的方式稱為OOP。面向過程(OP)和物件導向(OO)本質的區別在於分析方式的不同,最終導致了編碼方式的不同。  2.3 面向過程(OP)和物件導向(OO)
      關於面向過程的編程(OPP)和物件導向的編程(OOP),給出這它們的定義的人很多,您可以從任何資料中找到很專業的解釋,但以我的經驗來看,講的相對枯燥一點,不是很直觀。除非您已經有了相當的積累,否則說起來還是比較費勁。      我是個老程式員出身,雖然現在的日常工作更多傾向了管理,但至今依然保持編碼的習慣,這句話什麼意思呢?我跟大家溝通應該沒有問題。無論你是在重複我走過的路,或者已經走在了我的前面,大家都會有那麼一段相同的經曆,都會在思想層面上有一種理解和默契,所以我還是會盡量按照大多數人的常規思維寫下去。      面向過程的編程(OPP)產生在前,物件導向的編程(OOP)產生在後,所以物件導向的編程(OOP)一定會繼承前者的一些優點,並摒棄前者存在的一些缺點,這是符合人類進步的自然規律。兩者在各自的發展和演變過程中,也一定會相互借鑒,互相融合,來吸收對方優點,從而出現在某些方面的趨同性,這些是必然的結果。即使兩者有更多的相似點,也不會改變它們本質上的不同,因為它們的出發點就完全是兩種截然不同的思維方式。關於兩者的關係,我的觀點是這樣的:物件導向編程(OOP)在局部上一定是面向過程(OP)的,面向過程的編程(OPP)在整體上應該借鑒物件導向(OO)的思想。這一段說的的確很空洞,而且也一定會有引來爭議,不過,我勸您還是在閱讀了後面的內容之後,再來評判我觀點的正確與否。      象C++、C#、Java等都是物件導向的語言,c,php(暫且這麼說,因為php4以後就支援OO)都是面向過程的語言,那麼是不是我用C++寫的程式一定就是物件導向,用c寫的程式一定就是面向過程呢?這種觀點顯然是沒有真正吃透兩者的區別。語言永遠是一種工具,前輩們每創造出來的一種語言,都是你用來實現想法的利器。我覺得好多人用C#,Java寫出來的代碼,要是仔細看看,那實際就是用物件導向(OO)的語言寫的面向過程(OP)的程式。      所以,即使給關羽一根木棍,給你一杆青龍偃月刀,他照樣可以打得你滿頭是包。你就是扛著個偃月刀,也成不了關羽,因為你缺乏關羽最本質的東西---絕世武功。同樣的道理,如果你沒有領會OO思想,怎麼可能寫得出真正的OO程式呢?物件導向(OO)和面向過程(OP)絕對是兩種截然不同的思維方式。      那是不是面向過程就不好,也沒有存在的必要了?我從來沒有這樣說過。事實上,面向過程的編程(OPP)已經存在了幾十年了,現在依然有很多人在使用。它的優點就是邏輯不複雜的情況下很容易理解,而且運行效率遠高於物件導向(OO)編寫的程式。所以,系統級的應用或准即時系統中,依然採用面向過程的編程(OPP)。當然,很多編程高手以及大師級的人物,他們由於對於系統整體的掌控能力很強,也喜歡使用面向過程的編程(OPP),比如像Apache,QMail,PostFix,ICE等等這些比較經典的系統都是OPP的產物。      象php這些指令碼語言,主要用於web開發,對於一些商務邏輯相對簡單的系統,也常使用面向過程的編程(OPP),這也是php無法跨入到企業級應用開發的原因之一,不過php5目前已經能夠很好的支援OO了。  2.4 詳解面向過程的編程(OPP)
       在物件導向出現之前,我們採用的開發方法都是面向過程的編程(OPP)。面向過程的編程中最常用的一個分析方法是“功能分解”。我們會把使用者需求先分解成模組,然後把模組分解成大的功能,再把大的功能分解成小的功能,整個需求就是按照這樣的方式,最終分解成一個一個的函數。這種解決問題的方式稱為“自頂向下”,原則是“先整體後局部”,“先大後小”,也有人喜歡使用“自下向上”的分析方式,先解決局部痛點,逐步擴大開來,最後組合出來整個程式。其實,這兩種方式殊路同歸,最終都能解決問題,但一般情況下採用“自頂向下”的方式還是較為常見,因為這種方式最容易看清問題的本質。      我舉個例子來說明面向過程的編程方式:      使用者需求:老闆讓我寫個通用計算機。      終端使用者就是老闆,我作為程式員,任務就是寫一個計算機程式。OK,很簡單,以下就是用C語言完成的計算機:      假定程式的檔案名稱為:main.c。int main(int argc, char *argv[]){    //變數初始化
    int nNum1,nNum2;
    char cOpr;
    int nResult;
    nNum1 = nNum2 = 0;
    cOpr = 0;
    nResult = 0;    //輸入資料
    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);      //計算結果 
    if( cOpr == ‘+‘ ){
    nResult = nNum1 + nNum2;
    }else if( cOpr == ‘-‘ ){
    nResult = nNum1 - nNum2;
    }else{
    printf("Unknown operator!");
    return -1;
    }    //輸出結果
    printf("The result is %d!",nResult);
    return 0;
}        拋開細節不講,我想大多數人差不多都會這麼實現吧,很清晰,很簡單,充分體現了“簡單就是美”的原則,面向過程的編程就是這樣有條理的按照順序來逐步實現使用者需求。凡是做過程式的人都知道,使用者需求從來都不會是穩定的,最多隻能夠做到“相對穩定”。使用者可能會隨時提出加個功能,減個功能的要求,也可能會要求改動一下流程,程式員最煩的就是頻繁地變動需求,尤其是程式已經寫了大半了,但這種情況是永遠無法避免的,也不能完全歸罪到客戶或者需求分析師。      以我們上面的代碼為例,使用者可能會提出類似的要求:
      首先,你程式中實現了“加法”和“減法”,我還想讓它也能計算“乘法”、“除法”。
      其次,你現在的人機介面太簡單了,我還想要個Windows計算機的介面或者Mac計算機的介面。      使用者需求開始多了,我得琢磨琢磨該如何去寫這段代碼了。我今天加了“乘”“除”的運算,明天保不齊又得讓我加個“平方”、“立方”的運算,這要是把所有的運算都窮盡了,怎麼也得寫個千八百行代碼吧。還有,使用者要求介面能夠更換,還得寫一大堆介面產生的程式碼,又得來個千八百行。以後,這麼多代碼堆在一起,怎麼去維護,找個變數得半天,看懂了代碼得半天,萬一不小心改錯了,還得調半天。另外,介面設計我也不擅長,得找個更專業的人來做,做完了之後再加進來吧。這個過程也就是“軟體危機”產生的過程。伴隨著軟體廣泛地應用於各個領域,軟體開發的規模變得越來越大,複雜度越來越高,而其使用者的需求越來越不穩定。      根據使用者提出的兩個需求,面向過程的編程該如何去應對呢?我想大家都很清楚怎麼去改。Very easy,把“計算”和“介面”分開做成兩個獨立的函數,封裝到不同的檔案中。
      假定程式的檔案名稱為:main.c。#include "interface.h"
#include "calculate.h"
int main(int argc, char *argv[]){    //變數初始化
    int nNum1,nNum2;
    char cOpr;
    int nResult;
    nNum1 = nNum2 = 0;
    cOpr = 0;
    nResult = 0;    //輸入資料
    if( getParameters(&nNum1,&nNum2,&cOpr) == -1 )
    return -1;    //計算結果 
    if( calcMachine(nNum1,nNum2,cOpr,&nResult) == -1 )
    return -1;    //輸出結果
    printf("The result is %d!",nResult);    return 0;
} interface.h:
int getParameters(int *nNum1,int * nNum2,char *cOpr);interface.c:
int getParameters(int *nNum1,int * nNum2,char *cOpr){
    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);    return 0;
}calculate.h:
int calcMachine(int nNum1,int nNum2,char cOpr, int *nResult);calculate.c:
int calcMachine(int nNum1,int nNum2,char cOpr,int *nResult){
    if( cOpr == ‘+‘ ){
        *nResult = nNum1 + nNum2;
    }else if( cOpr == ‘-‘ ){
        *nResult = nNum1 - nNum2;
    }else{
        printf("Unknown operator!");
        return -1;
    };
    return 0;
}      面向過程的編程(OPP)就是將使用者需求進行“功能分解”。把使用者需求先分解成模組(.h,.c),再把模組(.h,.c)分解成大的功能(function),然後把大的功能(function)分解成小的功能(function),如此類推。      功能分解是一項很有技術含量的工作,它不僅需要分解者具有豐富的實戰經驗,而且需要科學的理論作為指導。如何分解,分解原則是什麼,模組粒度多大合適?這些都是架構師的要考慮的問題,也是我們後面要著重講的內容。面向過程的編程(OPP)優點是程式順序執行,流程清晰明了。它的缺點是主控程式承擔了太多的任務,各個模組都需要主控程式進行控制和調度,主控和模組之間的承擔的任務不均衡。
      有的人把面向流程定義為:演算法 + 資料結構,我覺得也很準確。面向過程的編程中演算法是核心,資料處於從屬地位,資料隨演算法而流動。所以採用面向過程的方式進行編程,一般在動手之前,都要編寫一份流程圖或是資料流圖。

.NET 進階架構師0002 架構師之路(1)---面向過程和物件導向

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.