在侃侃而談OO,侃侃而談設(shè)計(jì)模式,侃侃而談面向?qū)ο蟮闹T多原則之前,我們首先應(yīng)該掌握一點(diǎn):封裝。掌握好封裝的原則和技巧之后,就算使用的不是OO語言,也能構(gòu)造出框架優(yōu)美的程序。將這些原則用在程序之外,也能得到出奇的效果!对O(shè)計(jì)規(guī)則-模塊化的力量》(http://www.douban.com/subject/1737636/)將封裝與模塊化放在神壇的高位,它們配得上這個(gè)位置。這是我們解決復(fù)雜性問題的最基本的方法(沒有之一)。
程序是一種復(fù)雜性系統(tǒng)!暗郎唬簧,二生三,三生(四,四生…)萬物”。若將復(fù)雜性的根源當(dāng)作“道”的化,那么這個(gè)“一”必然是封裝。不同的程序語言以及由這些程序語言衍生的方法,則處于“二”的地位,比如 OO 設(shè)計(jì)范式、FP(函數(shù)編程)范式、分層的原則等等。OO設(shè)計(jì)準(zhǔn)則,什么里氏替換原則,什么組合優(yōu)先于繼承,這些處于“三”的地位,具體的設(shè)計(jì)模式什么之類的處于“三”之后“四”的地位。
本人愚笨,至今尚記不清那些原則,如里氏替換原則是什么,那些這個(gè)模式那個(gè)模式怎么實(shí)現(xiàn)。設(shè)計(jì)模式中,俺只對(duì)策略模式感興趣,對(duì)其它模式興趣索然。實(shí)質(zhì)上這些模式也好、準(zhǔn)則也好,只是給我們提供了一種方法、一種工具去更好的實(shí)現(xiàn)封裝。
復(fù)制和粘帖是封裝的大敵,是丑陋代碼的最大的壞味道。復(fù)制一份,就相當(dāng)于增加了至少一個(gè)可變點(diǎn),復(fù)制兩份就相當(dāng)于增加了至少兩個(gè)可變點(diǎn)。為什么說“至少”呢,因?yàn)槟K之間存在關(guān)聯(lián)關(guān)系,導(dǎo)致一個(gè)地方的變化會(huì)導(dǎo)致其它的多個(gè)地方也必須隨之變化。如果假定S為系統(tǒng)本身,M為對(duì)系統(tǒng)本身的一個(gè)測(cè)量,C為系統(tǒng)S中模塊的平均復(fù)制份數(shù)(C>1),則這個(gè)M與C的關(guān)系應(yīng)該是一個(gè)指數(shù)的關(guān)系: M正比于C的N次方(N>1)。
指數(shù)關(guān)系已經(jīng)很可怕了,更可怕的是,當(dāng)系統(tǒng)中的模塊出現(xiàn)變化時(shí),如果該模塊在系統(tǒng)中有多個(gè)副本,我們可能偷懶,只改變了其中的一個(gè)副本,而不是全部副本都進(jìn)行修改,這樣就導(dǎo)致模塊的分裂,由一個(gè)模塊分裂成幾個(gè)類似而又不同的模塊,大大的增加系統(tǒng)的復(fù)雜度,最終導(dǎo)致系統(tǒng)的腐爛。直覺上,一個(gè)設(shè)計(jì)很爛的系統(tǒng),它的復(fù)雜度大致是模塊數(shù)量的階乘關(guān)系甚至是冪指關(guān)系,這是比指數(shù)關(guān)系更恐怖的關(guān)系。
所以,復(fù)制和粘帖是一種非常邪惡的編碼方式。在編碼時(shí),需要千方百計(jì)的去想辦法減少復(fù)制和粘帖。這是在編碼時(shí)就應(yīng)該注意的問題,而不是放在重構(gòu)階段去做的事情。至于使用什么方法,使用什么手段,使用什么模式則是細(xì)節(jié)問題。
堅(jiān)持不復(fù)制和粘帖,堅(jiān)持下來,收益會(huì)非常大,寫出來的代碼質(zhì)量高、含金量高?匆妱e人的系統(tǒng),能馬上分辨出這個(gè)系統(tǒng)的優(yōu)點(diǎn)是什么,缺點(diǎn)是什么。什么設(shè)計(jì)模式也好,接口的正交性也好,設(shè)計(jì)原則也好,也許你從沒刻意的去學(xué)過,卻最終發(fā)現(xiàn)殊途同歸,冥冥之中與國外大牛有一種心意相通的感覺。會(huì)自發(fā)的去組合、去改良這些大牛們的思想和方法,甚至去創(chuàng)造新方法新手段。直接由一入手,一生二,二生三生四,而非教條的、頂禮膜拜的去學(xué)這個(gè)三,學(xué)這個(gè)四。或許那個(gè)時(shí)候,你已經(jīng)忘記什么是對(duì)象了。
之所以發(fā)這些牢騷,是因?yàn)樽蛱熘两裉,正在重?gòu)一個(gè)模塊。這個(gè)模塊M1的核心部件是一個(gè)包裝自RTF的layout規(guī)則編輯器。設(shè)計(jì)這個(gè)核心部件的哥們以RichTextBox為中心設(shè)計(jì)了一個(gè)控件A,然后將這個(gè)控件的部分規(guī)則邏輯抽出來放在類B和類C的靜態(tài)方法之中,更神奇的是這個(gè)類B是在另一個(gè)模塊M2之中,類C倒是在模塊M1之中。這個(gè)控件在M1中被三個(gè)地方給用到:D、E、F,這D、E、F每個(gè)地方都要為這個(gè)空間A注冊(cè)七八個(gè)事件,然后在事件的回調(diào)函數(shù)中調(diào)用模塊M2中的類B的靜態(tài)方法及模塊M1中的類C的靜態(tài)方法去實(shí)現(xiàn)一些邏輯,F(xiàn)在呢,我要寫一個(gè)控件G,這個(gè)G也要用到控件A,在這種情況下,我必需為G注冊(cè)一堆A的事件及回調(diào)函數(shù),然后在回調(diào)函數(shù)中弄一堆邏輯,至少得200行代碼。為了寫這些回調(diào)函數(shù),我必須得搞清這個(gè)A控件及類B,類C的內(nèi)部運(yùn)行機(jī)制。也就是說,為了吃豬肉必須得親自去殺豬。當(dāng)然,也可以從D、E或F 中Copy代碼過來改吧改吧來節(jié)省時(shí)間。
問題嚴(yán)重的地方在于,這個(gè)控件A本身存在邏輯錯(cuò)誤,存在功能不完善的地方,需要對(duì)它動(dòng)手術(shù)。因?yàn)榈教帍?fù)制,牽一發(fā)而動(dòng)全身,給A動(dòng)手術(shù)必須也要給B、C、D、E、F五個(gè)類動(dòng)手術(shù)。在給A動(dòng)手術(shù)時(shí),為了編譯通過,我將B、C、D、E、F中與A相關(guān)的代碼全給注釋掉了,前后注釋了1500行代碼左右。實(shí)質(zhì)上這1500行代碼真正有價(jià)值的代碼也就在200行左右,其它的代碼全是復(fù)制、粘帖,然后改改變量名完成的。
為什么會(huì)出現(xiàn)這樣的問題呢?因?yàn)閺?fù)制和粘帖。復(fù)制和粘帖省事啊,Copy過去改幾個(gè)詞就能用了,不用花費(fèi)心思的去想封裝。而實(shí)際情況是,要引用那個(gè)控件A,得寫200-300行代碼,多引用幾處,就得寫1000多行代碼,復(fù)制和粘帖的話倒不費(fèi)事,但如果發(fā)現(xiàn)這個(gè)A存在錯(cuò)誤,或者需要擴(kuò)展,在改A的同時(shí),同時(shí)也要?jiǎng)舆@1000多行代碼,這1000多行代碼中可能會(huì)牽扯到更多的代碼,最終導(dǎo)致必須修改更多的代碼,這便是代碼的腐爛。
其實(shí)這個(gè)A是很好封裝的,它不需要其它的類對(duì)它輸入任何輸入數(shù)據(jù),其它的類只需要從A控件中獲得一個(gè)最終的規(guī)則結(jié)果,一個(gè)List。封裝的好的話,調(diào)用A,獲得結(jié)果,兩三句代碼就可以實(shí)現(xiàn)。
之所以不封裝是因?yàn)榱?xí)慣了復(fù)制和粘帖,或者懶于去封裝,或者頭腦中根本沒封裝這根弦。
很多新程序員或者不新的程序員,尤其是Web開發(fā)程序員老抱怨工作的技術(shù)含量低,老是想學(xué)更多的東西。實(shí)質(zhì)上,他們所作的工作是非常有技術(shù)含量的東西,就看怎么看待。
如果只將自己的工作看作簡(jiǎn)單的復(fù)制、粘帖、抄襲、改代碼的話,自然技術(shù)含量低了。如果將自己的工作看作如何消除復(fù)制和粘帖、如何提高質(zhì)量、進(jìn)度,消除工作中的不必要事情,消除各種浪費(fèi),那么這個(gè)工作的技術(shù)含量是極其高的。不要膜拜大師,當(dāng)你這么做的時(shí)候,你做的正是大師的工作。不要膜拜新技術(shù),當(dāng)你這么做的時(shí)候,你的工作可能正是新新一代技術(shù)的萌芽。一點(diǎn)一滴、一色一香,全在心中。青青翠竹、盡是法身,郁郁黃花、無非般若。
本文鏈接:http://www.95time.cn/tech/program/2008/6308.asp
出處:獸族的榮耀
責(zé)任編輯:bluehearts
◎進(jìn)入論壇網(wǎng)絡(luò)編程版塊參加討論
|