架構(gòu)師之路

架構(gòu)師之路(1)面向過程和面向?qū)ο?/strong>

1、引言   機算機科學是一門應用科學,它的知識體系是典型的倒三角結(jié)構(gòu)苹威,所用的基礎(chǔ)知識并不多调违,只是隨著應用領(lǐng)域和方向的不同,產(chǎn)生了很多的分支,所以說編程并不是一件很困難的事情玷过,一個高中生經(jīng)過特定的訓練就可以做得到。但是,會編程和編好程絕對是兩碼事祸挪,同樣的程序員,有的人幾年之后成為了架構(gòu)師票顾,有的人卻還在不停地coding含鳞,只不過ctrl-c鸭廷、ctrl-v用得更加純熟了。在中國熔吗,編程人員最終的歸途無外乎兩條:一是轉(zhuǎn)向技術(shù)管理辆床,它的終點是CTO;二是繼續(xù)深入桅狠,它的終點是首席架構(gòu)師讼载,成為CEO的人畢竟是少數(shù)。如果你現(xiàn)在還是個普通的程序員中跌,希望繼續(xù)在技術(shù)這條路上前進的話咨堤,我想你還是應該先補充一點軟件工程的思想漩符,學習一點有關(guān)設(shè)計模式的知識陨仅,只有具備這些能力览祖,你才能從整體和宏觀層面來考慮問題耐薯、分析問題和解決問題痢虹。本人Coding了很多年畔勤,中間走了不少彎路仔掸,雖然最終沒什么大成就,但總算有一些心得起暮,很愿意把自己的一些經(jīng)驗拿出來跟大家分享卖氨,這或許對你的發(fā)展有所幫助。

由程序員轉(zhuǎn)為架構(gòu)師负懦,最繞不開的概念就算是面向?qū)ο?OO)了筒捺。記得在大學的時候,我們專業(yè)開了一門課叫《面向?qū)ο蟮木幊獭分嚼鳌D莻€時候系吭,我們剛剛學了一門C語言,開發(fā)環(huán)境用的還是DOS下的Turbo C颗品,半點項目開發(fā)的經(jīng)驗都沒有肯尺,純粹的空對空。所以躯枢,一學期下來则吟,我始終處于一種懵懂狀態(tài),既沒領(lǐng)會面向過程和面向?qū)ο蟮降子惺裁磪^(qū)別锄蹂,也沒搞懂面向?qū)ο竽軒硎裁春锰帯?/p>

2氓仲、面向過程(OP)和面向?qū)ο?OO) 2.1 蛋炒飯和蓋澆飯   有人這么形容OP和OO的不同:用面向過程的方法寫出來的程序是一份蛋炒飯,而用面向?qū)ο髮懗鰜淼某绦蚴且环萆w澆飯得糜。所謂蓋澆飯敬扛,北京叫蓋飯,東北叫燴飯朝抖,廣東叫碟頭飯啥箭,就是在一碗白米飯上面澆上一份蓋菜,你喜歡什么菜槽棍,你就澆上什么菜捉蚤。我覺得這個比喻還是比較貼切的抬驴。   蛋炒飯制作的細節(jié)炼七,我不太清楚,因為我沒當過廚師布持,也不會做飯豌拙,但最后的一道工序肯定是把米飯和雞蛋混在一起炒勻。蓋澆飯呢题暖,則是把米飯和蓋菜分別做好按傅,你如果要一份紅燒肉蓋飯呢捉超,就給你澆一份紅燒肉;如果要一份青椒土豆蓋澆飯唯绍,就給澆一份青椒土豆絲拼岳。   蛋炒飯的好處就是入味均勻,吃起來香况芒。如果恰巧你不愛吃雞蛋惜纸,只愛吃青菜的話,那么唯一的辦法就是全部倒掉绝骚,重新做一份青菜炒飯了耐版。蓋澆飯就沒這么多麻煩,你只需要把上面的蓋菜撥掉压汪,更換一份蓋菜就可以了粪牲。蓋澆飯的缺點是入味不均,可能沒有蛋炒飯那么香止剖。   到底是蛋炒飯好還是蓋澆飯好呢腺阳?其實這類問題都很難回答,非要比個上下高低的話穿香,就必須設(shè)定一個場景舌狗,否則只能說是各有所長。如果大家都不是美食家扔水,沒那么多講究痛侍,那么從飯館角度來講的話,做蓋澆飯顯然比蛋炒飯更有優(yōu)勢魔市,他可以組合出來任意多的組合主届,而且不會浪費。

2.2 軟件工程   蓋澆飯的好處就是“菜”“飯”分離待德,從而提高了制作蓋澆飯的靈活性君丁。飯不滿意就換飯,菜不滿意換菜将宪。用軟件工程的專業(yè)術(shù)語就是“可維護性”比較好绘闷,“飯”和“菜”的耦合度比較低。蛋炒飯將“蛋”“飯”攪和在一起较坛,想換“蛋”“飯”中任何一種都很困難印蔗,耦合度很高,以至于“可維護性”比較差丑勤。軟件工程追求的目標之一就是可維護性华嘹,可維護性主要表現(xiàn)在3個方面:可理解性、可測試性和可修改性法竞。面向?qū)ο蟮闹饕锰幘褪秋@著的改善了軟件的可維護性耙厚。

面向過程(OP)和面向?qū)ο?OO)是不是就是指編碼的兩種方式呢强挫?不是!你拿到了一個用戶需求薛躬,比如有人要找你編個軟件俯渤,你是不是需要經(jīng)過需求分析,然后進行總體/詳細設(shè)計型宝,最后編碼稠诲,才能最終寫出軟件,交付給用戶诡曙。這個過程是符合人類基本行為方式的:先想做什么臀叙,再想如何去做,最后才是做事情价卤。有的同學說:“我沒按照你說的步驟做啊劝萤,我是直接編碼的”。其實慎璧,你一定會經(jīng)歷了這三個階段床嫌,只不過你潛意識里沒有分得那么清楚。對于拿到需求就編碼的人胸私,可能編著編著厌处,又得倒回去重新琢磨,還是免不了這些過程岁疼,

以O(shè)O為例阔涉,對應于軟件開發(fā)的過程,OO衍生出3個概念:OOA捷绒、OOD和OOP瑰排。采用面向?qū)ο筮M行分析的方式稱為OOA,采用面向?qū)ο筮M行設(shè)計的方式稱為OOD暖侨,采用面向?qū)ο筮M行編碼的方式稱為OOP椭住。面向過程(OP)和面向?qū)ο?OO)本質(zhì)的區(qū)別在于分析方式的不同,最終導致了編碼方式的不同字逗。

2.3 面向過程(OP)和面向?qū)ο?OO)

架構(gòu)師之路(2)詳解面向過程

1. 面向過程編程(OPP) 和面向?qū)ο缶幊?OOP)的關(guān)系   關(guān)于面向過程的編程(OPP)和面向?qū)ο蟮木幊?OOP),給出這它們的定義的人很多京郑,您可以從任何資料中找到很專業(yè)的解釋,但以我的經(jīng)驗來看葫掉,講的相對枯燥一點些举,不是很直觀。除非您已經(jīng)有了相當?shù)姆e累挖息,否則說起來還是比較費勁金拒。

我是個老程序員出身兽肤,雖然現(xiàn)在的日常工作更多傾向了管理套腹,但至今依然保持編碼的習慣绪抛,這句話什么意思呢?我跟大家溝通應該沒有問題电禀。無論你是在重復我走過的路幢码,或者已經(jīng)走在了我的前面,大家都會有那么一段相同的經(jīng)歷尖飞,都會在思想層面上有一種理解和默契症副,所以我還是會盡量按照大多數(shù)人的常規(guī)思維寫下去。

面向過程的編程(OPP)產(chǎn)生在前政基,面向?qū)ο蟮木幊?OOP)產(chǎn)生在后贞铣,所以面向?qū)ο蟮木幊?OOP)一定會繼承前者的一些優(yōu)點,并摒棄前者存在的一些缺點沮明,這是符合人類進步的自然規(guī)律辕坝。兩者在各自的發(fā)展和演變過程中,也一定會相互借鑒荐健,互相融合酱畅,來吸收對方優(yōu)點,從而出現(xiàn)在某些方面的趨同性江场,這些是必然的結(jié)果纺酸。即使兩者有更多的相似點,也不會改變它們本質(zhì)上的不同址否,因為它們的出發(fā)點就完全是兩種截然不同的思維方式餐蔬。關(guān)于兩者的關(guān)系,我的觀點是這樣的:面向?qū)ο缶幊?OOP)在局部上一定是面向過程(OP)的佑附,面向過程的編程(OPP)在整體上應該借鑒面向?qū)ο?OO)的思想用含。這一段說的的確很空洞,而且也一定會有引來爭議帮匾,不過啄骇,我勸您還是在閱讀了后面的內(nèi)容之后,再來評判我觀點的正確與否瘟斜。

象C++缸夹、C#、Java等都是面向?qū)ο蟮恼Z言螺句,c,php(暫且這么說虽惭,因為php4以后就支持OO)都是面向過程的語言,那么是不是我用C++寫的程序一定就是面向?qū)ο笊呱校胏寫的程序一定就是面向過程呢芽唇?這種觀點顯然是沒有真正吃透兩者的區(qū)別。語言永遠是一種工具,前輩們每創(chuàng)造出來的一種語言匆笤,都是你用來實現(xiàn)想法的利器研侣。我覺得好多人用C#,Java寫出來的代碼,要是仔細看看炮捧,那實際就是用面向?qū)ο?OO)的語言寫的面向過程(OP)的程序庶诡。

所以,即使給關(guān)羽一根木棍咆课,給你一桿青龍偃月刀末誓,他照樣可以打得你滿頭是包。你就是扛著個偃月刀书蚪,也成不了關(guān)羽喇澡,因為你缺乏關(guān)羽最本質(zhì)的東西---絕世武功。同樣的道理殊校,如果你沒有領(lǐng)會OO思想撩幽,怎么可能寫得出真正的OO程序呢?面向?qū)ο?OO)和面向過程(OP)絕對是兩種截然不同的思維方式箩艺。

那是不是面向過程就不好窜醉,也沒有存在的必要了?我從來沒有這樣說過艺谆。事實上榨惰,面向過程的編程(OPP)已經(jīng)存在了幾十年了,現(xiàn)在依然有很多人在使用静汤。它的優(yōu)點就是邏輯不復雜的情況下很容易理解琅催,而且運行效率遠高于面向?qū)ο螅∣O)編寫的程序。所以虫给,系統(tǒng)級的應用或準實時系統(tǒng)中藤抡,依然采用面向過程的編程(OPP)。當然抹估,很多編程高手以及大師級的人物缠黍,他們由于對于系統(tǒng)整體的掌控能力很強,也喜歡使用面向過程的編程(OPP)药蜻,比如像Apache,QMail,PostFix,ICE等等這些比較經(jīng)典的系統(tǒng)都是OPP的產(chǎn)物瓷式。   象php這些腳本語言,主要用于web開發(fā)语泽,對于一些業(yè)務邏輯相對簡單的系統(tǒng)贸典,也常使用面向過程的編程(OPP),這也是php無法跨入到企業(yè)級應用開發(fā)的原因之一踱卵,不過php5目前已經(jīng)能夠很好的支持OO了廊驼。

2.詳解面向過程的編程(OPP)   在面向?qū)ο蟪霈F(xiàn)之前,我們采用的開發(fā)方法都是面向過程的編程(OPP)。面向過程的編程中最常用的一個分析方法是“功能分解”妒挎。我們會把用戶需求先分解成模塊绳锅,然后把模塊分解成大的功能,再把大的功能分解成小的功能饥漫,整個需求就是按照這樣的方式榨呆,最終分解成一個一個的函數(shù)罗标。這種解決問題的方式稱為“自頂向下”庸队,原則是“先整體后局部”,“先大后小”闯割,也有人喜歡使用“自下向上”的分析方式彻消,先解決局部難點,逐步擴大開來怨喘,最后組合出來整個程序裕菠。其實只锭,這兩種方式殊路同歸,最終都能解決問題煌贴,但一般情況下采用“自頂向下”的方式還是較為常見,因為這種方式最容易看清問題的本質(zhì)锥忿。

我舉個例子來說明面向過程的編程方式:   用戶需求:老板讓我寫個通用計算器牛郑。   最終用戶就是老板,我作為程序員敬鬓,任務就是寫一個計算器程序淹朋。OK,很簡單钉答,以下就是用C語言完成的計算器:   假定程序的文件名為: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:rn"); scanf("%d",&nNum1); printf("Please input the operator:rn"); scanf("%s",&cOpr); printf("Please input the second number:rn"); scanf("%d",&nNum2); //計算結(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; }

拋開細節(jié)不講,我想大多數(shù)人差不多都會這么實現(xiàn)吧数尿,很清晰仑性,很簡單,充分體現(xiàn)了“簡單就是美”的原則右蹦,面向過程的編程就是這樣有條理的按照順序來逐步實現(xiàn)用戶需求虏缸。   凡是做過程序的人都知道,用戶需求從來都不會是穩(wěn)定的嫩实,最多只能夠做到“相對穩(wěn)定”刽辙。用戶可能會隨時提出加個功能,減個功能的要求甲献,也可能會要求改動一下流程宰缤,程序員最煩的就是頻繁地變動需求,尤其是程序已經(jīng)寫了大半了,但這種情況是永遠無法避免的慨灭,也不能完全歸罪到客戶或者需求分析師朦乏。

以我們上面的代碼為例,用戶可能會提出類似的要求:   首先氧骤,你程序中實現(xiàn)了“加法”和“減法”呻疹,我還想讓它也能計算“乘法”、“除法”筹陵。   其次刽锤,你現(xiàn)在的人機界面太簡單了,我還想要個Windows計算器的界面或者Mac計算器的界面朦佩。   用戶需求開始多了并思,我得琢磨琢磨該如何去寫這段代碼了。我今天加了“乘”“除”的運算语稠,明天保不齊又得讓我加個“平方”宋彼、“立方”的運算,這要是把所有的運算都窮盡了仙畦,怎么也得寫個千八百行代碼吧输涕。還有,用戶要求界面能夠更換慨畸,還得寫一大堆界面生成的代碼莱坎,又得來個千八百行。以后先口,這么多代碼堆在一起型奥,怎么去維護,找個變量得半天碉京,看懂了代碼得半天厢汹,萬一不小心改錯了,還得調(diào)半天谐宙。另外烫葬,界面設(shè)計我也不擅長,得找個更專業(yè)的人來做凡蜻,做完了之后再加進來吧搭综。這個過程也就是“軟件危機”產(chǎn)生的過程。伴隨著軟件廣泛地應用于各個領(lǐng)域划栓,軟件開發(fā)的規(guī)模變得越來越大兑巾,復雜度越來越高,而其用戶的需求越來越不穩(wěn)定

根據(jù)用戶提出的兩個需求忠荞,面向過程的編程該如何去應對呢蒋歌?想大家都很清楚怎么去改帅掘。Very easy,把“計算”和“界面”分開做成兩個獨立的函數(shù)堂油,封裝到不同的文件中修档。   假定程序的文件名為: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; //輸入數(shù)據(jù) if( getParameters(&nNum1,&nNum2,&cOpr) == -1 ) return -1; //計算結(jié)果  if( calcMachine(nNum1,nNum2,cOpr,&nResult) == -1 ) return -1; //輸出結(jié)果 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:rn"); scanf("%d",nNum1); printf("Please input the operator:rn"); scanf("%s",cOpr); printf("Please input the second number:rn"); 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)迫靖,如此類推院峡。

功能分解是一項很有技術(shù)含量的工作,它不僅需要分解者具有豐富的實戰(zhàn)經(jīng)驗袜香,而且需要科學的理論作為指導撕予。如何分解鲫惶,分解原則是什么蜈首,模塊粒度多大合適?這些都是架構(gòu)師的要考慮的問題欠母,也是我們后面要著重講的內(nèi)容欢策。

面向過程的編程(OPP)優(yōu)點是程序順序執(zhí)行,流程清晰明了赏淌。它的缺點是主控程序承擔了太多的任務踩寇,各個模塊都需要主控程序進行控制和調(diào)度,主控和模塊之間的承擔的任務不均衡六水。

有的人把面向過程定義為:算法 + 數(shù)據(jù)結(jié)構(gòu)俺孙,我覺得也很準確。面向?qū)ο蟮木幊讨兴惴ㄊ呛诵闹兰郑瑪?shù)據(jù)處于從屬地位睛榄,數(shù)據(jù)隨算法而流動。所以采用面向過程的方式進行編程想帅,一般在動手之前场靴,都要編寫一份流程圖或是數(shù)據(jù)流圖。

如果大家對本文有意見盡可爭論港准,歡迎大家隨時拍磚旨剥。我有著鋼鐵一樣的心臟和城墻一樣的臉皮,承受能力極強浅缸,所以無論是支持意見還是反對反對意見轨帜,我都會認真閱讀,只要不是色情淫穢和反動言論衩椒,我盡量不刪貼蚌父。由于個人能力和時間有限蚕礼,也只能寫到這樣的水平了,大家諒解梢什。我的資料里有qq號奠蹬,加為好友后就可以看到,我的qq對任何人開放嗡午。 架

構(gòu)師之路(3)架構(gòu)師的職責

架構(gòu)師的職責   近來看到CSDN上有個CTO俱樂部囤躁,里面聊得是不亦樂乎。我懷著無比崇敬的態(tài)度荔睹,拜讀了一下牛人們的發(fā)言狸演。里面有個哥們發(fā)起一個話題:“CTO, 你多久沒有寫程序了?”僻他。有人回答:“不寫代碼的CTO,屬于......這公司問題大了!”宵距。看到這里吨拗,我就趕緊撤了满哪,怕忍不住反駁幾句,反而遭到牛人們的群毆劝篷。試想哨鸭,一個上點規(guī)模的IT公司,還得靠CTO來寫程序的話娇妓,那是不是才叫問題大了呢像鸡。當然,我沒有做過CTO哈恰,所以我有我的不同看法只估,而且還愿意表達出來,無知者無畏着绷。我情愿相信:我所理解的CTO跟這位CTO所理解的是兩回事蛔钙。所以我想,如果有人能把CTO的職責給標準化了蓬戚,也許就不會有這么多的爭論了夸楣。   同樣的道理,關(guān)于架構(gòu)師的定義子漩,大家也有著不同的理解豫喧。什么是架構(gòu)師?架構(gòu)師有哪些職責幢泼?我覺得有必要提前明確一下紧显,要不然大家溝通起來也會產(chǎn)生類似問題,子說子理缕棵,卯說卯理孵班,但是壓根說得不是一碼子事涉兽。

1 什么是架構(gòu)師   曾經(jīng)有這么個段子:   甲:我已經(jīng)應聘到一家中型軟件公司了,今天上班的時候篙程,全公司的人都來歡迎我枷畏。   乙:羨慕ing,都什么人來了虱饿?   甲:CEO拥诡、COO、CTO氮发、All of 程序員渴肉,還有會計、司機都來了爽冕。   乙:哇仇祭,他們太重視你了,人才啊颈畸,這么多人迎接你乌奇!   甲:沒有啊,就一個人承冰!   乙:靠华弓,#%¥$%...

很多的創(chuàng)業(yè)公司食零,一人身兼數(shù)職的情形還是很常見的困乒。至少,我是經(jīng)歷過的贰谣,一個人包辦了所有的開發(fā)過程娜搂,連測試我都做了,絕對的一條龍吱抚,但是經(jīng)常踩鋼絲百宇、騎獨輪車總會有失足的時候,結(jié)果有一次秘豹,從我手里發(fā)出去的光盤母盤携御,含有病毒僵尸,以至于被迫收回已經(jīng)推上市場的2萬張光盤既绕,從那之后啄刹,我的心臟就開始變得無比堅強,現(xiàn)在就是整個后臺服務都癱瘓了凄贩,我也只是微微一笑誓军。其實,一個人身兼架構(gòu)師和程序員疲扎,甚至多種角色昵时,沒什么不妥捷雕,后面還會講這個話題,這種現(xiàn)象不是中國特色壹甥,跟國外是完全接軌的救巷。我曾經(jīng)跟米國的一個工程師在msn中聊過類似的話題,發(fā)現(xiàn)他們的路子跟咱們沒什么不同句柠,在IT這個行業(yè)征绸,我們跟世界的差距只有1天,他們剛弄出來的新東西俄占,我們這里第2天保準見得到管怠。

架構(gòu)師這個稱呼不是拍腦袋想出來的,是有國際標準(ISO/IEC 42010)可查的缸榄。架構(gòu)師是軟件開發(fā)活動中的眾多角色之一渤弛,它贍蓯且桓鋈恕⒁桓魴∽樯醮部贍蓯且桓鐾哦铀稀N⑷磯約芄故τ幸桓齜擲嗖慰跡頤遣慰家幌攏前鴨芄故Ψ治?種:企業(yè)架構(gòu)師EA(Enterprise Architect)、基礎(chǔ)結(jié)構(gòu)架構(gòu)師IA(Infrastructure Architect)鹰贵、特定技術(shù)架構(gòu)TSA(Technology-Specific Architect)和解決方案架構(gòu)師SA (Solution Architect)晴氨。微軟的這個分類是按照架構(gòu)師專注的領(lǐng)域不同而劃分的。

EA的職責是決定整個公司的技術(shù)路線和技術(shù)發(fā)展方向碉输。蓋茨給自己的Title就是首席軟件架構(gòu)師籽前,網(wǎng)易丁磊也喜歡這么稱呼自己,實際上就是EA角色敷钾;IA的工作就是提煉和優(yōu)化技術(shù)方面積累和沉淀形成的基礎(chǔ)性的枝哄、公共的、可復用的框架和組件阻荒,這些都是一個技術(shù)型公司傳承下來的最寶貴的財富之一挠锥;特定技術(shù)架構(gòu)師TSA,他們主要從事類似安全架構(gòu)侨赡、存儲架構(gòu)等專項技術(shù)的規(guī)劃和設(shè)計工作蓖租;SA的工作則專于解決方案的規(guī)劃和設(shè)計,“解決方案”這個詞在中國已經(jīng)到了嚴重泛濫的程度羊壹,大忽悠們最喜歡把它掛在嘴邊蓖宦。所謂解決方案,就是把產(chǎn)品舶掖、技術(shù)或理論球昨,不斷地進行組合,來創(chuàng)造出滿足用戶需求的選擇眨攘。售前工程師一般都是帶著它到客戶那里去發(fā)揮的主慰。

大公司會把各種類型的架構(gòu)師分得很清楚嚣州,小公司一般就不那么講究了,架構(gòu)師多數(shù)是是IA+TSA+SA共螺,一人包打天下该肴,所以說大公司出專才,小公司出全才藐不。   實際工作中匀哄,我們也經(jīng)常會見到另一種比較簡單的分類方式,把架構(gòu)師分為軟件架構(gòu)師和系統(tǒng)架構(gòu)師雏蛮。軟件架構(gòu)師基本上是TSA+IA涎嚼,這也是程序員最容易突破,最可能走上的一條道路挑秉,比如JAVA架構(gòu)師法梯、DotNet架構(gòu)師、LAPM架構(gòu)師等等犀概,我后面所講的內(nèi)容都是與軟件架構(gòu)師的相關(guān)的話題立哑。系統(tǒng)架構(gòu)師實際上是SA+TSA,更著力于綜合運用已有的產(chǎn)品和技術(shù)姻灶,來實現(xiàn)客戶期望的需求铛绰。系統(tǒng)架構(gòu)師要求通曉軟、硬件兩方面的知識产喉,所以它的知識體系相對龐雜捂掰。關(guān)于系統(tǒng)架構(gòu)師的話題,我們可以稍后再作討論镊叁。

2 架構(gòu)師的職責   架構(gòu)師主要職責有4條: 1尘颓、確認需求   在項目開發(fā)過程中,架構(gòu)師是在需求規(guī)格說明書完成后介入的晦譬,需求規(guī)格說明書必須得到架構(gòu)師的認可。架構(gòu)師需要和分析人員反復交流互广,以保證自己完整并準確地理解用戶需求敛腌。

2、系統(tǒng)分解   依據(jù)用戶需求惫皱,架構(gòu)師將系統(tǒng)整體分解為更小的子系統(tǒng)和組件像樊,從而形成不同的邏輯層或服務。隨后旅敷,架構(gòu)師會確定各層的接口生棍,層與層相互之間的關(guān)系。架構(gòu)師不僅要對整個系統(tǒng)分層媳谁,進行“縱向”分解涂滴,還要對同一邏輯層分塊友酱,進行“橫向”分解。   軟件架構(gòu)師的功力基本體現(xiàn)于此柔纵,這是一項相對復雜的工作缔杉。

3、技術(shù)選型   架構(gòu)師通過對系統(tǒng)的一系列的分解搁料,最終形成了軟件的整體架構(gòu)或详。技術(shù)選擇主要取決于軟件架構(gòu)。 Web Server運行在Windows上還是Linux上郭计?數(shù)據(jù)庫采用MSSql霸琴、Oracle還是Mysql?需要不需要采用MVC或者Spring等輕量級的框架昭伸?前端采用富客戶端還是瘦客戶端方式沈贝?類似的工作,都需要在這個階段提出勋乾,并進行評估宋下。   架構(gòu)師對產(chǎn)品和技術(shù)的選型僅僅限于評估,沒有決定權(quán)辑莫,最終的決定權(quán)歸項目經(jīng)理学歧。架構(gòu)師提出的技術(shù)方案為項目經(jīng)理提供了重要的參考信息,項目經(jīng)理會從項目預算各吨、人力資源枝笨、時間進度等實際情況進行權(quán)衡,最終進行確認揭蜒。

4横浑、制定技術(shù)規(guī)格說明   架構(gòu)師在項目開發(fā)過程中,是技術(shù)權(quán)威屉更。他需要協(xié)調(diào)所有的開發(fā)人員徙融,與開發(fā)人員一直保持溝通,始終保證開發(fā)者依照它的架構(gòu)意圖去實現(xiàn)各項功能瑰谜。   架構(gòu)師不僅要保持與開發(fā)者的溝通欺冀,也需要與項目經(jīng)理、需求分析員萨脑,甚至與最終用戶保持溝通隐轩。所以,對于架構(gòu)師來講渤早,不僅有技術(shù)方面的要求职车,還有人際交流方面的要求。

3 架構(gòu)師的誤區(qū) 1、架構(gòu)師就是項目經(jīng)理   架構(gòu)師不是項目經(jīng)理悴灵。項目經(jīng)理側(cè)重于預算控制扛芽、時間進度控制、人員管理称勋、與外部聯(lián)系和協(xié)調(diào)等等工作胸哥,具備管理職能。一般小型項目中赡鲜,常見項目經(jīng)理兼架構(gòu)師空厌。

2、架構(gòu)師負責需求分析   架構(gòu)師不是需求分析員银酬。需求分析人員的工作是收集需求和分析需求嘲更,并與最終用戶、產(chǎn)品經(jīng)理保持聯(lián)系揩瞪。架構(gòu)師只對最終的需求審核和確認赋朦,提出需求不清和不完整的部分,他會跟需求分析員時刻保持聯(lián)系李破。架構(gòu)師是技術(shù)專家宠哄,不是業(yè)務專家。

3嗤攻、架構(gòu)師從來不寫代碼   這是一個尚存爭論的問題毛嫉。目前有兩種觀點:   觀點1:架構(gòu)師不寫代碼,寫代碼純體力活妇菱,架構(gòu)師寫代碼大材小用承粤。架構(gòu)師把UML的各種視圖交給開發(fā)人員,如果有不明確的地方闯团,可以與架構(gòu)師隨時溝通辛臊。   觀點2:架構(gòu)師本來自于程序員,只是比程序員站的層面更高房交,比程序員唯一多的是經(jīng)驗和知識彻舰,所以架構(gòu)師也免不了寫代碼。   我個人覺得這兩種說法是與架構(gòu)師的出身和所處的環(huán)境有關(guān)涌萤。   架構(gòu)師首先是一個技術(shù)角色淹遵,所以一定是來自于技術(shù)人員這個群體,比如系統(tǒng)架構(gòu)師负溪,多是來自于運維人員,可能本身代碼寫得并不多济炎,或者說寫不出來很漂亮的代碼川抡。軟件架構(gòu)師多是來自于程序員,有著程序員的血統(tǒng)和情懷,所以在項目開發(fā)過程中崖堤,可能會寫一些核心代碼侍咱。我們的理想是架構(gòu)師不用寫代碼,但事實上有時候過于理想密幔。架構(gòu)師寫不寫代碼楔脯,可能取決于公司的規(guī)模、文化胯甩、開發(fā)人員的素質(zhì)等現(xiàn)實情況昧廷。另外,架構(gòu)師也不是跟程序員界限分得那么清楚偎箫,按照能力也有高中低之分木柬,寫不寫代碼不是區(qū)分兩者的根本標準。

4 架構(gòu)師的基本素質(zhì) 1淹办、溝通能力   為了提高效率眉枕,架構(gòu)師必須贏得團隊成員怜森、項目經(jīng)理速挑、客戶或用戶認同,這就需要架構(gòu)師具有較強的溝通能力副硅。溝通能力是人類最普遍性的素質(zhì)要求姥宝,技術(shù)人員好像容易忽略,想成為架構(gòu)師就不能忽略想许。千萬不要抱著這樣的觀念:懷才跟懷孕似的伶授,時間久了總會被人發(fā)現(xiàn)的。還是天橋上賣大力丸的哥們說得對:光說不練假把式流纹,光練不說傻把式糜烹。看看你周圍的頭頭腦腦們漱凝,哪一個不是此中高手疮蹦,我們千萬不要鄙視,認為這是阿諛奉承茸炒、投機鉆營愕乎,凡事都要看到積極的一面,“溝通”的確是一種能力壁公。我認為自己是一個略內(nèi)向的人感论,因為我是農(nóng)村出來的孩子,普通話都說不好紊册,以前或多或少帶有點自卑感比肄,幻想著是金子總會發(fā)光,所以在職業(yè)生涯中吃了不少虧。現(xiàn)在芳绩,我深深懂得了溝通的重要性掀亥,我會很主動地跟同事們,跟老大們不定時地溝通妥色,感覺工作起來順暢多了搪花。   這一條我認為最為重要,所以排在首位嘹害。我甚至認為下面幾條都可以忽略撮竿,唯一這一條得牢記,而且要常常提醒自己吼拥。

2倚聚、領(lǐng)導能力   架構(gòu)師能夠推動整個團隊的技術(shù)進展,能在壓力下作出關(guān)鍵性的決策凿可,并將其貫徹到底惑折。架構(gòu)師如何來保證這種執(zhí)行力?這就需要架構(gòu)師具有領(lǐng)導能力枯跑。   架構(gòu)師的領(lǐng)導能力的取得跟項目經(jīng)理不太一樣惨驶。項目經(jīng)理主要負責解決行政管理,這種能力與技術(shù)關(guān)系不大敛助,他有人權(quán)和財權(quán)粗卜,再扯上一張“領(lǐng)導”的虎皮,采用“胡蘿卜加大棒”的方式纳击,基本上可以保證執(zhí)行力续扔。架構(gòu)師在項目里面可能更多地使用非正式的領(lǐng)導力,也就是我們常說的影響力焕数,里面包括個人魅力纱昧、技術(shù)能力、知識傳遞等等堡赔。

3识脆、抽象思維和分析能力   架構(gòu)師必須具備抽象思維和分析的能力,這是你進行系統(tǒng)分析和系統(tǒng)分解的基本素質(zhì)善已。只有具備這樣的能力灼捂,架構(gòu)師才能看清系統(tǒng)的整體,掌控全局换团,這也是架構(gòu)師大局觀的形成基礎(chǔ)悉稠。你如何具備這種能力呢?一是來自于經(jīng)驗艘包,二是來自于學習偎球。架構(gòu)師不僅要具備在問題領(lǐng)域上的經(jīng)驗洒扎,也需要具備在軟件工程領(lǐng)域內(nèi)的經(jīng)驗辑甜。也就是說衰絮,架構(gòu)師必須能夠準確得理解需求,然后用軟件工程的思想磷醋,把需求轉(zhuǎn)化和分解成可用計算機語言實現(xiàn)的程度猫牡。經(jīng)驗的積累是需要一個時間過程的,這個過程誰也幫不了你邓线,是需要你去經(jīng)歷的淌友。但是,如果你有意識地去培養(yǎng)骇陈,不斷吸取前人的經(jīng)驗的話震庭,還是可以縮短這個周期的。這也是我寫作此系列的始動力之一你雌。

4器联、技術(shù)深度和廣度   架構(gòu)師最好精通1-2個技術(shù),具備這種技術(shù)能力可以更加深入的理解有關(guān)架構(gòu)的工作原理婿崭,也可以拉近和開發(fā)人員的距離拨拓,并形成團隊中的影響力。   架構(gòu)師的技術(shù)知識廣度也很重要氓栈,需要了解盡可能多的技術(shù)渣磷,所謂見多識廣,只有這樣授瘦,才可能綜合各種技術(shù)醋界,選擇更加適合項目的解決方案。有的人說提完,架構(gòu)師技術(shù)廣度的要求高于技術(shù)深度的要求形纺,這是很有道理的。

總而言之,一句話:架構(gòu)師是項目團隊中的技術(shù)權(quán)威。   面向過程和面向?qū)ο筮@兩個基本概念束倍,不僅架構(gòu)師需要非常清楚脆诉,程序員、設(shè)計師也要非常清楚藻治,這也是系統(tǒng)分析、設(shè)計和編碼最基本的常識。我接觸的程序員戏羽,很多人只停留在一種“似是而非”的程度,這是不行的楼吃,想要繼續(xù)前進始花,就得把基礎(chǔ)夯實妄讯,所以我覺得很有必要先回回爐,補補課酷宵。

后記:在講面向?qū)ο笾皩懥诉@么一篇亥贸,主要就是要把前面漏下的功課補上。

架構(gòu)師之路(4)詳解面向?qū)ο?/strong>

詳解面向?qū)ο蟮木幊?OOP) 1 什么是面向?qū)ο?   剛接觸編程的時候浇垦,多數(shù)人本能的反映可能是面向過程(OP)的炕置,而不是面向?qū)ο?OO)的。這種現(xiàn)象其實是很正常的男韧,改變思維方式是需要一個過程的朴摊,我大體歸納了一下其形成的原因: 1、直接原因   你還沒有養(yǎng)成面向?qū)ο蠓治鰡栴}和解決問題的習慣此虑。建立面向?qū)ο蟮乃季S方式需要一定時間的訓練和揣摩才能形成甚纲,所以你可以在學習或具體項目中刻意地強化這種意識。一般情況下朦前,經(jīng)過一段時間之后介杆,你會覺得這是自然而然的事情,只有心中OO况既,眼中自然OO了这溅。

2、歷史原因   我們從小接受的培訓都是采用面向過程(OP)的方式分析問題和解決問題棒仍,尤其是數(shù)學悲靴,多數(shù)是強調(diào)按部就班的解決問題,計算機軟件的發(fā)展一直就與數(shù)學是很有淵源莫其,所以癞尚,順理成章的,把面向過程(OP)的方式帶入到軟件開發(fā)也是很自然的事情乱陡。

什么是面向?qū)ο蠼娇蛘哒務勀銓γ嫦驅(qū)ο蟮睦斫猓@恐怕是軟件開發(fā)人員憨颠,尤其是程序員和設(shè)計師應聘的時候胳徽,面試官常最掛在嘴邊的問題吧。面向?qū)ο髮挠⑽氖荗bject-Oriented爽彤,把Object-Oriented翻譯成“面向?qū)ο蟆毖粒乙恢庇X得這個譯法不太確切,因為多數(shù)人第一次看到“面向?qū)ο蟆边@四個字适篙,都很難從字面上理解它到底是什么意思往核。后來,我又查閱了一些有關(guān)的資料嚷节,發(fā)現(xiàn)港澳臺的計算機書籍中是把它翻譯成了“物件導向”聂儒,這個譯法虎锚,我感覺不錯,于我心頗有些戚戚焉衩婚〈芑ぃ“物件導向”比較準確地反映了面向?qū)ο笳J識和解決問題都是要圍繞對象展開的。

所以谅猾,面向?qū)ο蟮乃季S方式認為:軟件系統(tǒng)是一組交互的對象的集合柄慰。一組相關(guān)的對象組合為一個子系統(tǒng),一組子系統(tǒng)繼續(xù)組合為更復雜的子系統(tǒng)税娜,直至組合成整個系統(tǒng)。

面向?qū)ο蠓绞降某霭l(fā)點是盡可能模擬人類習慣的思維方式藏研,將“問題域”中涉及的內(nèi)容抽象為“對象”谷砑⒌姆椒ㄓ牘嘆】贍芙詠死噯鮮妒瀾緗餼鑫侍獾姆椒ㄓ牘獺?/p>   面向過程就是分析出解決問題所需要的步驟敬矩,然后用函數(shù)把這些步驟一步一步實現(xiàn),使用的時候一個一個依次調(diào)用就可以了蠢挡。面向?qū)ο笫前褬?gòu)成問題事務分解成各個對象弧岳,建立對象的目的不是為了完成一個步驟,而是為了描敘某個事物在整個解決問題的步驟中的行為业踏。   面向過程認識和解決問題的思維禽炬,可以稱為“流程論”,重點放在處理過程的步驟勤家,流程是整個系統(tǒng)的核心腹尖。

面向?qū)ο笳J識和解決問題的思維,可以稱為“組裝論”伐脖,重心放在對象的抽象和提取上热幔,然后將對象組裝為整體。   所以O(shè)O和OP從思維方式來講讼庇,出發(fā)點還是完全不同的绎巨。

2 OP PK OO   咱們用象棋對戰(zhàn)的例子,來比較OP和OO的不同: http://img.ddvip.com/2009_03_06/1236333416_ddvip_6956.jpeg   紅方:功夫熊貓 黑方:悍嬌虎 裁判:龜仙人   采用面向過程(OPP)的設(shè)計思路蠕啄,首先分拆整個對戰(zhàn)過程场勤,分析雙方對戰(zhàn)的步驟,得到如下流程: http://img.ddvip.com/2009_03_06/1236333416_ddvip_1731.jpeg   把上面每個步驟分別用函數(shù)進行實現(xiàn)歼跟,問題就解決了和媳。   我們再來看看面向?qū)ο笫侨绾蝸斫鉀Q問題,整個象棋游戲可以抽象出3種對象: 1嘹承、棋手窗价,負責行棋,這兩者行為一致叹卷。 2撼港、棋盤坪它,負責繪制棋盤畫面。 3帝牡、裁判往毡,負責判定諸如吃子、犯規(guī)和輸贏靶溜。

三者之間的關(guān)系如下: http://img.ddvip.com/2009_03_06/1236333416_ddvip_219.jpeg   第一類對象棋手負責行棋开瞭,并告知第二類對象棋盤中棋子布局的變化,棋盤接收到了棋子布局的變化后罩息,負責在繪制屏幕嗤详,同時利用第三類對象裁判來對棋局進行判定。

從以上兩種的實現(xiàn)方式可以看出幾點: 1瓷炮、可維護性   面向?qū)ο笫且詳?shù)據(jù)和功能來劃分問題葱色,而不是依據(jù)流程和步驟。同樣是繪制棋盤的行為娘香,在面向過程的設(shè)計中分散在了很多的步驟中苍狰,很可能出現(xiàn)在不同的繪制版本中,只是不是很像一份“蛋炒飯”中的雞蛋烘绽?在面向?qū)ο蟮脑O(shè)計中淋昭,繪圖只可能在棋盤對象中出現(xiàn),從而保證了繪圖的統(tǒng)一安接,這就是把雞蛋從“蛋炒飯”中分離出來的效果翔忽。

2、可擴展性   假如我要加入悔棋的功能赫段,如果要改動面向過程的設(shè)計呀打,那么從行棋到顯示再到判定這一連串的步驟都要改動,甚至步驟之間的循序都要進行大規(guī)模調(diào)整糯笙。如果是面向?qū)ο蟮脑挶岽裕挥酶膭悠灞P對象就行了,棋盤對象保存了雙方的棋譜给涕,簡單回溯豺憔,減一就可以了,而顯示和判定不涉及够庙,同時整體對各個對象功能的調(diào)用順序都沒有變化恭应,改動只限定在了局部。

3 深層思考   認為:軟件系統(tǒng)是一組交互的對象的集合耘眨。   因為人類對現(xiàn)實世界是非常熟悉的昼榛,所以O(shè)O就是通過抽象的方式,把問題域映射到現(xiàn)實世界剔难,盡量模擬現(xiàn)實世界的萬事萬物胆屿。通過這種方式奥喻,就可以運用現(xiàn)實世界中解決問題的方法與過程,來解決軟件領(lǐng)域內(nèi)的問題非迹。

有人說:OO眼里一切皆對象环鲤,這句話還是很有道理的。   到底給軟件開發(fā)帶來了什么樣的好處憎兽?OO的抽象的尺度是如何把握的呢冷离?這都是問題。

架構(gòu)師之路(5)面向?qū)ο蟮脑O(shè)計原則

1 OO的設(shè)計原則   采用面向?qū)ο蟮姆治龊驮O(shè)計思想纯命,為我們分析和解決問題提供了一種全新的思維方式西剥。我們在拿到需求之后(略去OOA,以后補全)扎附,接下來的問題就是:如何對系統(tǒng)進行面向?qū)ο蟮脑O(shè)計呢蔫耽?

按照軟件工程的理論,面向?qū)ο蟮脑O(shè)計要解決的核心問題就是可維護性和可復用性留夜。尤其是可維護性,它是影響軟件生命周期重要因素图甜,通常情況下碍粥,軟件的維護成本遠遠大于初期開發(fā)成本。

一個可維護性很差的軟件設(shè)計黑毅,人們通常稱之為“臭味”的嚼摩,形成的原因主要有這么幾個:過于僵硬、過于脆弱矿瘦、復用率低或者黏度過高枕面。相反,一個好的系統(tǒng)設(shè)計應該是靈活的缚去、可擴展的潮秘、可復用的、可插拔的易结。在20世紀80到90年代枕荞,很多業(yè)內(nèi)專家不斷探索面向?qū)ο蟮能浖O(shè)計方法,陸續(xù)提出了一些設(shè)計原則搞动。這些設(shè)計原則能夠顯著地提高系統(tǒng)的可維護性和可復用性躏精,成為了我們進行面向?qū)ο笤O(shè)計的指導原則:

1、 單一職責原則SRP   每一個類應該只專注于做一件事鹦肿。 2矗烛、 “開-閉”原則OCP   每一個類應該是對擴展開放,對修改關(guān)閉箩溃。 3瞭吃、 里氏代換原則LSP   避免造成派生類的方法非法或退化碌嘀,一個基類的用戶應當不需要知道這個派生類。 4虱而、 依賴倒轉(zhuǎn)原則DIP   用依賴于接口和抽象類來替代依賴容易變化的具體類筏餐。 5、 接口隔離原則ISP   應當為客戶提供盡可能小的接口牡拇,而不是提供大的接口魁瞪。

其中,“開-閉”原則是面向?qū)ο蟮目蓮陀迷O(shè)計的基石惠呼,其他設(shè)計原則是實現(xiàn)“開-閉”原則的手段和工具导俘。   我會為大家一一進行講解。 2 單一職責原則SRP(Single-Responsibility Principle) 2.1什么是單一職責   單一職責就是指一個類應該專注于做一件事√尢#現(xiàn)實生活中也存謚釗绱死嗟奈侍猓?ldquo;一個人可能身兼數(shù)職旅薄,甚至于這些職責彼此關(guān)系不大,那么他可能無法做好所有職責內(nèi)的事情泣崩,所以少梁,還是專人專管比較好〗酶叮”我們在設(shè)計類的時候凯沪,就應該遵循這個原則:單一職責。

我們以計算器編程為例:   在有些人眼里买优,計算器就是一件東西妨马,是一個整體,所以它把這個需求進行了抽象杀赢,最終設(shè)計為一個Calculator類烘跺,代碼如下: class Calculator{ public String calculate() { Console.Write("Please input the first number:"); String strNum1 = Console.ReadLine(); Console.Write(Please input the operator:"); String strOpr= Console.ReadLine(); Console.Write("Please input the second number:"); String strNum2 = Console.ReadLine(); String strResult = ""; if (strOpr == "+"){ strResult = Convert.ToString(Convert.ToDouble(strNum1) + Convert.ToDouble(strNum2)); } else if (strOpr == "-"){ strResult = Convert.ToString(Convert.ToDouble(strNum1) - Convert.ToDouble(strNum2)); } else if (strOpr == "*"){ strResult = Convert.ToString(Convert.ToDouble(strNum1) * Convert.ToDouble(strNum2)); } else if (strOpr == "/"){ strResult = Convert.ToString(Convert.ToDouble(strNum1) / Convert.ToDouble(strNum2)); } Console.WriteLine("The result is " + strResult); }}   另外,還有一部分人認為:計算器是一個外殼和一個處理器的組合脂崔。 class Appearance{ public int displayInput(String &strNum1,String &strOpr, String &strNum2) { Console.Write("Please input the first number:"); strNum1 = Console.ReadLine(); Console.Write(Please input the operator:"); strOpr= Console.ReadLine(); Console.Write("Please input the second number:"); strNum2 = Console.ReadLine(); return 0; }

public String displayOutput(String strResult) { Console.WriteLine("The result is " + strResult); } } class Processor{ public String calculate(String strNum1,String strOpr, String strNum2){ String strResult = ""; if (strOpr == "+"){ strResult = Convert.ToString(Convert.ToDouble(strNum1) + Convert.ToDouble(strNum2)); } else if (strOpr == "-"){ strResult = Convert.ToString(Convert.ToDouble(strNum1) - Convert.ToDouble(strNum2)); } else if (strOpr == "*"){ strResult = Convert.ToString(Convert.ToDouble(strNum1) * Convert.ToDouble(strNum2)); } else if (strOpr == "/"){ strResult = Convert.ToString(Convert.ToDouble(strNum1) / Convert.ToDouble(strNum2)); } return strResult; } }   為什么這么做呢滤淳?因為外殼和處理器是兩個職責,都是很容易發(fā)生需求變動的因素脱篙,所以把他們放到一個嘀薪壳ケ沉說ヒ恢霸鷦頡?/p>

比如,用戶可能對計算器提出以下要求:   第一绊困,目前已經(jīng)實現(xiàn)了“加法”文搂、“減法”、“乘法”和“除法”秤朗,以后還可能出現(xiàn)“乘方”煤蹭、“開方”等很多運算。

第二,現(xiàn)在人機界面太簡單了硝皂,還可能做個Windows計算器風格的界面或者Mac計算器風格的界面常挚。   所以,把一個類Calculator 拆分為兩個類Appearance和Processor稽物,更容易應對需求變化奄毡。如果界面需要修改,那么就去修改Appearance類贝或;如果處理器需要修改吼过,那么就去修改Processor類。   我們再舉一個郵件的例子咪奖。我們平常收到的郵件內(nèi)容盗忱,看起來是一封信,實際上內(nèi)部有兩部分組成:郵件頭和郵件體羊赵。電子郵件的編碼要求符合RFC822標準趟佃。   第一種設(shè)計方式是這樣: interface IEmail { public void setSender(String sender); public void setReceiver(String receiver); public void setContent(String content); } class Email implements IEmail { public void setSender(String sender) {// set sender; } public void setReceiver(String receiver) {// set receiver; } public void setContent(String content) {// set content; } }

這個設(shè)計是有問題的,因為郵件頭和郵件體都有變化的可能性昧捷。 1闲昭、郵件頭的每一個域的編碼,可能是BASE64靡挥,也可能是QP汤纸,而且域的數(shù)量也不固定。 2芹血、郵件體中封裝的郵件內(nèi)容可能是PlainText類型,也可能是HTML類型,甚至于流媒體楞慈。   所謂第一種設(shè)計方式違背了單一職責原則幔烛,里面封裝了兩種可能引起變化的原因。   我們依照單一職責原則囊蓝,對其進行改進后饿悬,變?yōu)榈诙N設(shè)計方式: interface IEmail { public void setSender(String sender); public void setReceiver(String receiver); public void setContent(IContent content); } interface IContent { public String getAsString(); } class Email implements IEmail { public void setSender(String sender) {// set sender; } public void setReceiver(String receiver) {// set receiver; } public void setContent(IContent content) {// set content; } }   有的資料把單一職責解釋為:“僅有一個引起它變化的原因”。這個解釋跟“專注于做一件事”是等價的聚霜。如果一個類同時做兩件事情狡恬,那么這兩件事情都有可能引起它的變化。同樣的道理蝎宇,如果僅有一個引起它變化的原因弟劲,那么這個類也就只能做一件事情。

2.2單一職責原則的使用   單一職責原則的尺度如何掌握呢姥芥?我怎么能知道該拆分還是不應該拆分呢兔乞?原則很簡單:需求決定。如果你所需要的計算器,永遠都沒有外觀和處理器變動的可能性庸追,那么就應該把它抽象為一個整體的計算器霍骄;如果你所需要的計算器,外殼和處理器都有可能發(fā)生變動淡溯,那么就必須把它拆離為外殼和處理器读整。只能有一個原因可能引起計算器的變化。   單一職責原則把相同的職責進行聚合咱娶,避免把相同的職責分散到不同的類之中米间,這樣就可以控制變化,把變化限制在一個地方豺总,防止因為一個地方的變動车伞,引起更多地方的變動的“漣漪效應”。單一職責原則實際上消除了對象之間的耦合喻喳,避免一個類承擔過多的職責另玖。單一職責不是說一個類就只有一個方法,而是單一功能表伦。

我們在使用單一職責原則的時候谦去,牢記以下幾點: A、一個設(shè)計合理的類蹦哼,應該僅有一個可以引起它變化的原因鳄哭,即單一職責,如果有多個原因可以引起它的變化纲熏,就必須進行分離妆丘; B、在沒有需求變化征兆的情況下局劲,應用SRP或其他原則是不明智的勺拣,因為這樣會使系統(tǒng)變得很復雜,系統(tǒng)由一堆細小的顆粒組成鱼填,這純屬于沒事找抽药有; C、在需求能夠預計或?qū)嶋H發(fā)生變化時苹丸,就應該使用SRP原則來重構(gòu)代碼愤惰,有經(jīng)驗的設(shè)計師、架構(gòu)師對可能出現(xiàn)的需求變化很敏感赘理,設(shè)計上就會具有前瞻性宦言。   后記:最近看了一個“現(xiàn)場說法”的電視節(jié)目,著實有意思感憾。說是最近有兩個偷車大盜被我警方抓獲蜡励。這倆大盜都是賊中高手令花,非常了得,不過凉倚,他們卻有著不同的成長路線兼都。

其中一個大盜,苦心鉆研開鎖技術(shù)稽寒,專門去香港學習先進技術(shù)扮碧,前后花了一百多萬,非常舍得投資杏糙,回來后屢屢得手慎王。另一個大盜,就比較狡猾宏侍,整天到商場的停車場赖淤,跟隨著寶馬、奔馳的車主谅河,在車主購物的時候咱旱,伺機偷去車鑰匙,然后從停車場把車開走绷耍,案發(fā)的時候案值達到了千萬吐限。呵呵,看來干什么事褂始,都得找到關(guān)鍵所在诸典。

架構(gòu)師之路(6)OOD的開閉原則

開閉原則(Open-Closed Principle,OCP) 1 什么是開閉原則   開閉原則是面向?qū)ο笤O(shè)計中“可復用設(shè)計”的基石,是面向?qū)ο笤O(shè)計中最重要的原則之一崎苗,其它很多的設(shè)計原則都是實現(xiàn)開閉原則的一種手段狐粱。 1988年,Bertrand Meyer在他的著作《Object Oriented Software Construction》中提出了開閉原則胆数,它的原文是這樣:“Software entities should be open for extension,but closed for modification”脑奠。翻譯過來就是:“軟件實體應當對擴展開放,對修改關(guān)閉”幅慌。這句話說得略微有點專業(yè),我們把它講得更通俗一點轰豆,也就是:軟件系統(tǒng)中包含的各種組件胰伍,例如模塊(Modules)、類(Classes)以及功能(Functions)等等酸休,應該在不修改現(xiàn)有代碼的基礎(chǔ)上骂租,引入新功能。開閉原則中“開”斑司,是指對于組件功能的擴展是開放的渗饮,是允許對其進行功能擴展的;開閉原則中“閉”,是指對于原有代碼的修改是封閉的互站,即不應該修改原有的代碼私蕾。

2 如何實現(xiàn)開閉原則   實現(xiàn)開閉原則的關(guān)鍵就在于“抽象”。把系統(tǒng)的所有可能的行為抽象成一個抽象底層胡桃,這個抽象底層規(guī)定出所有的具體實現(xiàn)必須提供的方法的特征踩叭。作為系統(tǒng)設(shè)計的抽象層,要預見所有可能的擴展翠胰,從而使得在任何擴展情況下容贝,系統(tǒng)的抽象底層不需修改;同時之景,由于可以從抽象底層導出一個或多個新的具體實現(xiàn)斤富,可以改變系統(tǒng)的行為,因此系統(tǒng)設(shè)計對擴展是開放的锻狗。

我們在軟件開發(fā)的過程中满力,一直都是提倡需求導向的。這就要求我們在設(shè)計的時候屋谭,要非常清楚地了解用戶需求脚囊,判斷需求中包含的可能的變化,從而明確在什么情況下使用開閉原則桐磁。

關(guān)于系統(tǒng)可變的部分悔耘,還有一個更具體的對可變性封裝原則(Principle of Encapsulation of Variation, EVP),它從軟件工程實現(xiàn)的角度對開閉原則進行了進一步的解釋我擂。EVP要求在做系統(tǒng)設(shè)計的時候衬以,對系統(tǒng)所有可能發(fā)生變化的部分進行評估和分類,每一個可變的因素都單獨進行封裝校摩。

我們在實際開發(fā)過程的設(shè)計開始階段看峻,就要羅列出來系統(tǒng)所有可能的行為,并把這些行為加入到抽象底層衙吩,根本就是不可能的互妓,這么去做也是不經(jīng)濟的,費時費力坤塞。另外冯勉,在設(shè)計開始階段,對所有的可變因素進行預計和封裝也不太現(xiàn)實摹芙,也是很難做得到灼狰。所以,開閉原則描繪的愿景只是一種理想情況或是極端狀態(tài)浮禾,現(xiàn)實世界中是很難被完全實現(xiàn)的交胚。我們只能在某些組件份汗,在某種程度上符合開閉原則的要求。

通過以上的分析蝴簇,對于開閉原則杯活,我們可以得出這樣的結(jié)論:雖然我們不可能做到百分之百的封閉,但是在系統(tǒng)設(shè)計的時候军熏,我們還是要盡量做到這一點轩猩。   對于軟件系統(tǒng)的功能擴展,我們可以通過繼承荡澎、重載或者委托等手段實現(xiàn)均践。以接口為例,它對修改就是是封閉的摩幔,而對具體的實現(xiàn)是開放的彤委,我們可以根據(jù)實際的需要提供不同的實現(xiàn),所以接口是符合開閉原則的或衡。

3 開閉原則能夠帶來什么好處   如果一個軟件系統(tǒng)符合開閉原則的焦影,那么從軟件工程的角度來看,它至少具有這樣的好處:   可復用性好封断。   我們可以在軟件完成以后斯辰,仍然可以對軟件進行擴展,加入新的功能坡疼,非常靈活彬呻。因此,這個軟件系統(tǒng)就可以通過不斷地增加新的組件柄瑰,來滿足不斷變化的需求闸氮。   可維護性好。   由于對于已有的軟件系統(tǒng)的組件教沾,特別是它的抽象底層不去修改蒲跨,因此,我們不用擔心軟件系統(tǒng)中原有組件的穩(wěn)定性授翻,這就使變化中的軟件系統(tǒng)有一定的穩(wěn)定性和延續(xù)性或悲。

4 開閉原則與其它原則的關(guān)系   開閉原則具有理想主義的色彩,它是面向?qū)ο笤O(shè)計的終極目標堪唐。因此隆箩,針對開閉原則的實現(xiàn)方法,一直都有面向?qū)ο笤O(shè)計的大師費盡心機羔杨,研究開閉原則的實現(xiàn)方式。后面要提到的里氏代換原則(LSP)杨蛋、依賴倒轉(zhuǎn)原則(DIP)兜材、接口隔離原則(ISP)以及抽象類(Abstract Class)理澎、接口(Interace)等等,都可以看作是開閉原則的實現(xiàn)方法曙寡。

文章我是轉(zhuǎn)發(fā)的糠爬,如有侵權(quán),我必刪除

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末举庶,一起剝皮案震驚了整個濱河市执隧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌户侥,老刑警劉巖镀琉,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蕊唐,居然都是意外死亡屋摔,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門替梨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钓试,“玉大人,你說我怎么就攤上這事副瀑」” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵糠睡,是天一觀的道長挽鞠。 經(jīng)常有香客問我,道長铜幽,這世上最難降的妖魔是什么滞谢? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮除抛,結(jié)果婚禮上狮杨,老公的妹妹穿的比我還像新娘。我一直安慰自己到忽,他們只是感情好橄教,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著喘漏,像睡著了一般护蝶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上翩迈,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天持灰,我揣著相機與錄音,去河邊找鬼负饲。 笑死堤魁,一個胖子當著我的面吹牛喂链,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播妥泉,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼椭微,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了盲链?” 一聲冷哼從身側(cè)響起蝇率,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤刽沾,失蹤者是張志新(化名)和其女友劉穎本慕,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體间狂,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年骡男,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片犹菱。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡陕凹,死狀恐怖鳄炉,靈堂內(nèi)的尸體忽然破棺而出佑女,到底是詐尸還是另有隱情团驱,我是刑警寧澤店茶,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布丛楚,位于F島的核電站憔辫,受9級特大地震影響坏平,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜顾瞪,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一钉跷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸歹颓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽兜粘。三九已至距糖,卻和暖如春帽氓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背势腮。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工吗浩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留懂扼,地道東北人。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓眶诈,卻偏偏與公主長得像宪潮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355