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