先考慮一個(gè)現(xiàn)實(shí)問(wèn)題, 大家都熟悉的手機(jī)發(fā)短信. 來(lái)看看早期(A 大約是匯編語(yǔ)言時(shí)代),中期(B 結(jié)構(gòu)化),現(xiàn)在(C 面向?qū)ο?三種思想下的不同實(shí)現(xiàn).
我說(shuō)的是思想, 因?yàn)殡m然現(xiàn)在大家使用著面向?qū)ο蟮墓ぞ?但是大部分程序員的思想依然沒(méi)有面向?qū)ο? 比如現(xiàn)在我手下這群程序員里有面向?qū)ο蠓治龊驮O(shè)計(jì)能力的也就一個(gè)..
用最面向?qū)ο骿ava和C#也可以寫(xiě)出雜亂無(wú)章完全不面向?qū)ο笊踔敛唤Y(jié)構(gòu)化的程序.
注意到現(xiàn)在我們的手機(jī)號(hào)碼分成移動(dòng)和聯(lián)通兩種, 雖然對(duì)我們來(lái)說(shuō),不過(guò)是號(hào)碼不一樣收費(fèi)不太一樣,沒(méi)多少區(qū)別,但是兩家的短信接口可是完全不一樣的.
假設(shè)程序要求 用戶在界面上輸入手機(jī)號(hào)碼(TextBox1),輸入一條短信內(nèi)容(TextBox2),按確定(Button1),就可以把短信發(fā)到那個(gè)手機(jī)上
A 一步一步走,該干什么就干什么...看看偽代碼:
st***號(hào)碼 = TextBox1.Text;
st***內(nèi)容 = TextBox2.Text;
int 第3位數(shù)字 = int.Parse(號(hào)碼.Substring(2,1)); //把第3位取出來(lái),用來(lái)判斷是不是移動(dòng)的手機(jī) 如 1390000000 就取出一個(gè) 9
if(第3位數(shù)字 > 3)
{
....
....
....//這里是一堆長(zhǎng)長(zhǎng)的代碼用來(lái)發(fā)送***的短信...省略,我們這里只說(shuō)程序的思想..不涉及技術(shù)細(xì)節(jié)
}
else
{
....
...
...//又是一堆長(zhǎng)長(zhǎng)的代碼用來(lái)發(fā)送***的短信
}
B 寫(xiě)一個(gè)庫(kù),定義出發(fā)送***短信的函數(shù)和發(fā)送***短信的函數(shù),還有判斷的函數(shù),假設(shè)函數(shù)原型分別是
發(fā)送移動(dòng)短信(st***手機(jī)號(hào)碼,st***內(nèi)容);
發(fā)送聯(lián)通短信(st***手機(jī)號(hào)碼,st***內(nèi)容);
bool 是否是移動(dòng)號(hào)碼(st***手機(jī)號(hào)碼);
然后寫(xiě)程序如下:
if(是否是移動(dòng)號(hào)碼(TextBox1.Text))
發(fā)送移動(dòng)短信(TextBox1.Text,TextBox2.Text);
else
發(fā)送聯(lián)通短信(TextBox1.Text,TextBox2.Text);
C 定義一個(gè)抽象接口 "短信接收者", 由 "***"和 "***" 兩個(gè)類分別實(shí)現(xiàn)接口. 各自實(shí)現(xiàn)發(fā)送短信方法.
然后構(gòu)造一個(gè) "手機(jī)工廠"(一時(shí)想不到好的名字,暫時(shí)叫這個(gè)吧) , 接收一個(gè)號(hào)碼,返回一個(gè) "短信接收者"接口(里面根據(jù)接收的參數(shù),可能是***或***)
然后程序如下(一行..):
手機(jī)工廠.獲取接受者(TextBox1.Text).發(fā)送(TextBox2.Text);
或?qū)懗蛇@樣清晰點(diǎn):
st***號(hào)碼 = TextBox1.Text;
st***內(nèi)容 = TextBox2.Text;
手機(jī)工廠.獲取接受者(號(hào)碼).發(fā)送(內(nèi)容);
OK,對(duì)于上面3段偽代碼 大家有什么想法? 第3種是不是看起來(lái)有點(diǎn) 爽? 也許把,也僅僅是看起來(lái)那么一點(diǎn)爽,沒(méi)什么大不了.
沒(méi)錯(cuò),面向?qū)ο笫窃诖笮偷牡胤礁荏w現(xiàn)優(yōu)勢(shì),一小堆是展現(xiàn)不出來(lái)的. 我們假設(shè)程序中一共有100個(gè)這樣的地方(比如一個(gè)是發(fā)短信的,一個(gè)接短信的,一個(gè)打電話的,一個(gè)上網(wǎng)的.....)
那么對(duì)于A程序,很抱歉,非常要命,要在100個(gè)地方復(fù)制代碼,復(fù)制100份,然后對(duì)其中99份做修改(或多或少,總要改點(diǎn)..)
B程序只是在每個(gè)調(diào)用的地方加幾行,可以接受.
C程序在調(diào)用點(diǎn)也是加1行,同樣也可以接受.
這個(gè)時(shí)候,結(jié)構(gòu)化和面向?qū)ο蠊餐膬?yōu)點(diǎn)體現(xiàn)出來(lái)了,復(fù)用性 (教科書(shū)中講面向?qū)ο罂偸钦f(shuō)說(shuō)復(fù)用是面向?qū)ο蟊绕渌椒ǖ膬?yōu)勢(shì),其實(shí)結(jié)構(gòu)化本身就是可復(fù)用的)
A方法差不多該拋棄了........這就是結(jié)構(gòu)化發(fā)展起來(lái)以后, 非結(jié)構(gòu)化很快面臨淘汰地步的原因,因?yàn)樵谲浖晕⒋簏c(diǎn),就出麻煩,寫(xiě)寫(xiě)單片機(jī)小模塊還行.
軟件在一天天變大變復(fù)雜,僅僅是變大變復(fù)雜而已? 當(dāng)然不是. 也變得多變. 用戶的需求時(shí)時(shí)在變.軟件也容易變,.
回到剛才的問(wèn)題, 現(xiàn)在不是有小靈通么? 你又需要多一種類型,變成 小靈通\移動(dòng)\聯(lián)通 3種類型.
那么對(duì)于 A ,災(zāi)難發(fā)生....修改程序的成本不比重新做一個(gè)少.
對(duì)于B 需要去100個(gè)調(diào)用的地方多加一個(gè)if來(lái)判斷,然后多加一個(gè)對(duì)應(yīng)小靈通的函數(shù). 修改量有點(diǎn)大,不過(guò)也不是不行,因?yàn)楫吘宫F(xiàn)在的工具發(fā)達(dá),你可以查找--替換.
不過(guò)程序是需要測(cè)試的,你替換一個(gè)地方,就需要多測(cè)試一個(gè)地方,成本高.
對(duì)于C 多加一個(gè)實(shí)現(xiàn) 接口的 "小靈通" 類 , 然后修改 "手機(jī)工廠"的 "獲取接受者(st***號(hào)碼)". 一共2處,測(cè)試也只要再測(cè)試 這個(gè)新類 還有一個(gè)方法.
C 方法 面向?qū)ο蟮膬?yōu)勢(shì)在這個(gè)時(shí)候體現(xiàn)出來(lái)了.
有人這個(gè)時(shí)候出來(lái)*了,如果程序?qū)懙亩嗔?經(jīng)驗(yàn)豐富了,有人會(huì)看出我上面那些假設(shè)的漏洞,就是B 并不是的結(jié)構(gòu)化方法, 因?yàn)?其實(shí)有更好的用一個(gè)函數(shù)來(lái)實(shí)現(xiàn)判斷類型
那樣就跟 C 一樣,只要改很少的地方了.
沒(méi)錯(cuò), 那樣C和B又公平平等了,C還是沒(méi)什么優(yōu)勢(shì). 請(qǐng)注意2點(diǎn) 第一: "面向?qū)ο? 不是指 面向?qū)ο?的 編程語(yǔ)法, 而是一種思想. 那樣寫(xiě)其實(shí) B 已經(jīng)拿到了一點(diǎn)面向?qū)ο蟮乃枷肓?BR> 只是封裝在非面向?qū)ο蟮恼Z(yǔ)法中. 第二 不面向?qū)ο蟮拇_可以寫(xiě)出低耦合的,高效的,可維護(hù)的,很牛逼的程序. 但是那是需要很高造詣的人來(lái)做的事. 因?yàn)闆](méi)有類的封裝性,名字空間的隔絕
我說(shuō)的是思想, 因?yàn)殡m然現(xiàn)在大家使用著面向?qū)ο蟮墓ぞ?但是大部分程序員的思想依然沒(méi)有面向?qū)ο? 比如現(xiàn)在我手下這群程序員里有面向?qū)ο蠓治龊驮O(shè)計(jì)能力的也就一個(gè)..
用最面向?qū)ο骿ava和C#也可以寫(xiě)出雜亂無(wú)章完全不面向?qū)ο笊踔敛唤Y(jié)構(gòu)化的程序.
注意到現(xiàn)在我們的手機(jī)號(hào)碼分成移動(dòng)和聯(lián)通兩種, 雖然對(duì)我們來(lái)說(shuō),不過(guò)是號(hào)碼不一樣收費(fèi)不太一樣,沒(méi)多少區(qū)別,但是兩家的短信接口可是完全不一樣的.
假設(shè)程序要求 用戶在界面上輸入手機(jī)號(hào)碼(TextBox1),輸入一條短信內(nèi)容(TextBox2),按確定(Button1),就可以把短信發(fā)到那個(gè)手機(jī)上
A 一步一步走,該干什么就干什么...看看偽代碼:
st***號(hào)碼 = TextBox1.Text;
st***內(nèi)容 = TextBox2.Text;
int 第3位數(shù)字 = int.Parse(號(hào)碼.Substring(2,1)); //把第3位取出來(lái),用來(lái)判斷是不是移動(dòng)的手機(jī) 如 1390000000 就取出一個(gè) 9
if(第3位數(shù)字 > 3)
{
....
....
....//這里是一堆長(zhǎng)長(zhǎng)的代碼用來(lái)發(fā)送***的短信...省略,我們這里只說(shuō)程序的思想..不涉及技術(shù)細(xì)節(jié)
}
else
{
....
...
...//又是一堆長(zhǎng)長(zhǎng)的代碼用來(lái)發(fā)送***的短信
}
B 寫(xiě)一個(gè)庫(kù),定義出發(fā)送***短信的函數(shù)和發(fā)送***短信的函數(shù),還有判斷的函數(shù),假設(shè)函數(shù)原型分別是
發(fā)送移動(dòng)短信(st***手機(jī)號(hào)碼,st***內(nèi)容);
發(fā)送聯(lián)通短信(st***手機(jī)號(hào)碼,st***內(nèi)容);
bool 是否是移動(dòng)號(hào)碼(st***手機(jī)號(hào)碼);
然后寫(xiě)程序如下:
if(是否是移動(dòng)號(hào)碼(TextBox1.Text))
發(fā)送移動(dòng)短信(TextBox1.Text,TextBox2.Text);
else
發(fā)送聯(lián)通短信(TextBox1.Text,TextBox2.Text);
C 定義一個(gè)抽象接口 "短信接收者", 由 "***"和 "***" 兩個(gè)類分別實(shí)現(xiàn)接口. 各自實(shí)現(xiàn)發(fā)送短信方法.
然后構(gòu)造一個(gè) "手機(jī)工廠"(一時(shí)想不到好的名字,暫時(shí)叫這個(gè)吧) , 接收一個(gè)號(hào)碼,返回一個(gè) "短信接收者"接口(里面根據(jù)接收的參數(shù),可能是***或***)
然后程序如下(一行..):
手機(jī)工廠.獲取接受者(TextBox1.Text).發(fā)送(TextBox2.Text);
或?qū)懗蛇@樣清晰點(diǎn):
st***號(hào)碼 = TextBox1.Text;
st***內(nèi)容 = TextBox2.Text;
手機(jī)工廠.獲取接受者(號(hào)碼).發(fā)送(內(nèi)容);
OK,對(duì)于上面3段偽代碼 大家有什么想法? 第3種是不是看起來(lái)有點(diǎn) 爽? 也許把,也僅僅是看起來(lái)那么一點(diǎn)爽,沒(méi)什么大不了.
沒(méi)錯(cuò),面向?qū)ο笫窃诖笮偷牡胤礁荏w現(xiàn)優(yōu)勢(shì),一小堆是展現(xiàn)不出來(lái)的. 我們假設(shè)程序中一共有100個(gè)這樣的地方(比如一個(gè)是發(fā)短信的,一個(gè)接短信的,一個(gè)打電話的,一個(gè)上網(wǎng)的.....)
那么對(duì)于A程序,很抱歉,非常要命,要在100個(gè)地方復(fù)制代碼,復(fù)制100份,然后對(duì)其中99份做修改(或多或少,總要改點(diǎn)..)
B程序只是在每個(gè)調(diào)用的地方加幾行,可以接受.
C程序在調(diào)用點(diǎn)也是加1行,同樣也可以接受.
這個(gè)時(shí)候,結(jié)構(gòu)化和面向?qū)ο蠊餐膬?yōu)點(diǎn)體現(xiàn)出來(lái)了,復(fù)用性 (教科書(shū)中講面向?qū)ο罂偸钦f(shuō)說(shuō)復(fù)用是面向?qū)ο蟊绕渌椒ǖ膬?yōu)勢(shì),其實(shí)結(jié)構(gòu)化本身就是可復(fù)用的)
A方法差不多該拋棄了........這就是結(jié)構(gòu)化發(fā)展起來(lái)以后, 非結(jié)構(gòu)化很快面臨淘汰地步的原因,因?yàn)樵谲浖晕⒋簏c(diǎn),就出麻煩,寫(xiě)寫(xiě)單片機(jī)小模塊還行.
軟件在一天天變大變復(fù)雜,僅僅是變大變復(fù)雜而已? 當(dāng)然不是. 也變得多變. 用戶的需求時(shí)時(shí)在變.軟件也容易變,.
回到剛才的問(wèn)題, 現(xiàn)在不是有小靈通么? 你又需要多一種類型,變成 小靈通\移動(dòng)\聯(lián)通 3種類型.
那么對(duì)于 A ,災(zāi)難發(fā)生....修改程序的成本不比重新做一個(gè)少.
對(duì)于B 需要去100個(gè)調(diào)用的地方多加一個(gè)if來(lái)判斷,然后多加一個(gè)對(duì)應(yīng)小靈通的函數(shù). 修改量有點(diǎn)大,不過(guò)也不是不行,因?yàn)楫吘宫F(xiàn)在的工具發(fā)達(dá),你可以查找--替換.
不過(guò)程序是需要測(cè)試的,你替換一個(gè)地方,就需要多測(cè)試一個(gè)地方,成本高.
對(duì)于C 多加一個(gè)實(shí)現(xiàn) 接口的 "小靈通" 類 , 然后修改 "手機(jī)工廠"的 "獲取接受者(st***號(hào)碼)". 一共2處,測(cè)試也只要再測(cè)試 這個(gè)新類 還有一個(gè)方法.
C 方法 面向?qū)ο蟮膬?yōu)勢(shì)在這個(gè)時(shí)候體現(xiàn)出來(lái)了.
有人這個(gè)時(shí)候出來(lái)*了,如果程序?qū)懙亩嗔?經(jīng)驗(yàn)豐富了,有人會(huì)看出我上面那些假設(shè)的漏洞,就是B 并不是的結(jié)構(gòu)化方法, 因?yàn)?其實(shí)有更好的用一個(gè)函數(shù)來(lái)實(shí)現(xiàn)判斷類型
那樣就跟 C 一樣,只要改很少的地方了.
沒(méi)錯(cuò), 那樣C和B又公平平等了,C還是沒(méi)什么優(yōu)勢(shì). 請(qǐng)注意2點(diǎn) 第一: "面向?qū)ο? 不是指 面向?qū)ο?的 編程語(yǔ)法, 而是一種思想. 那樣寫(xiě)其實(shí) B 已經(jīng)拿到了一點(diǎn)面向?qū)ο蟮乃枷肓?BR> 只是封裝在非面向?qū)ο蟮恼Z(yǔ)法中. 第二 不面向?qū)ο蟮拇_可以寫(xiě)出低耦合的,高效的,可維護(hù)的,很牛逼的程序. 但是那是需要很高造詣的人來(lái)做的事. 因?yàn)闆](méi)有類的封裝性,名字空間的隔絕

