面向對象思想(2)

從我們最初接觸面向對象思想的時候,我想我們接觸到的第一個概念應該就是“”,我們一直在討論諸如如何設計類、如何實現類等高深的問題,但是我們有沒有思索過到底什麼叫做“類”,類的本質是什麼?。按照大多數的面向對象的書籍中的介紹來看,類就是一個數據結構,封裝了數據和操作,對於這樣的答案,我估計大家都不會滿意。
    那到底什麼是類呢?在討論這個問題之前,我們先探討一下類的由來。“”在英語對應的單詞是“Class”,如果大家翻一翻英語詞典就可以查到“Class”的原意是指“種類、把...分類(或分等級)”。Class的概念最早應該是從分類學來的,意思是把對象進行歸類(說的可能有些不太準確,歡迎那位高人指正),例如生物學上會根據某一個標準將生物分爲動物和植物兩大類,然後再根據其它的一些標準將動物又分爲魚類、爬行動物類、兩棲動物類等不同的種類,如下圖所示:

    說到這裏,可能大家會歡呼:原來面向對象的類就是分類,太好了!我最擅長這個了!別高興的太早,誰知道面向對象的分類標準是什麼嗎?是生物學的標準,還是能不能爬樹的標準?不同的標準,導致分類的結果完全不同,如下圖所示:

    假設現在需要要寫一個彈塗魚的類(又名蝦虎魚,英文名爲Goby,一種可以爬上陸地並且會上樹的魚類,據說味道極其鮮美,有海上人蔘之說) ,怎麼寫?是不是太容易了,看下面的代碼,分分鐘就搞定了:

 1 '
 2 Public Class Fish
 3 
 4 End Class
 5 
 6 '可爬樹的魚
 7 Public Class ClimbableFish
 8     Inherits Fish
 9 
10 End Class
11 
12 '彈塗魚
13 Public Class Goby
14     Inherits ClimbableFish
15 
16 End Class

    打完收功,貌似很完美的解決問題,但是這個時候又添加了一個分類標準,能吃的魚和不能吃的魚(鯊魚能吃,俺吃過,味道不咋地,在這裏假設鯊魚不能吃),又該怎麼辦,Stupid,再寫一個“EatableFish” 類不就得了,讓可愛的彈塗魚從可以吃的魚派生,我最喜歡能吃的魚了!且慢!動手之前我想搞清楚一個問題:EatableFish從那個類派生?從 ClimbableFish類派生?難道可以吃的魚都是會爬樹的魚?從Fish派生,那麼是不是說會爬樹的魚都不能吃?這個時候是不是該咒罵微軟爲什麼不 在.NET中支持多重繼承?算了,還是轉投Java陣營算了。旁邊的一位兄弟弱弱的來了一句:好像Java也不支持多重繼承吧。怎麼辦?難道我們就沒有辦 法解決這個問題了嗎?
    貌似用分類學的搞法搞不定面向對象的類耶,我們錯了嗎?但是很多教科書上面就是這麼說的類的繼承是“Is A”(是一個)的關係呀,彈塗魚是“Is A”能吃的魚、彈塗魚“Is A” 能爬樹的魚,念起來蠻通順的嘛。錯了!我們都被教科書給誤導了!面向對象關注什麼?關注的是對象的行爲,面向對象是使用行爲來對對象進行分類的!在面向對 象中派生類爲什麼能夠替換基類(替換原則),不是因爲派生類是一個基類,而是因爲派生類具有與基類一致的行爲,在派生類與基類的行爲不一致的情況下派生類 仍然是一個基類(如果有人敢否認這個,大家說怎麼辦?旁邊有人喊道:砍死他!),但是這個時候派生類消減了基類的行爲,違背了替換原則,這也是噁心設計的 由來。所以說,對於面向對象而言我們要關注“Act As”,用“Act As”的標準來對對象進行歸類,至於什麼“Is A”之類的僞標準統統扔到它姥姥家去。
    旁邊有人不幹了:你跟我說說屬性是什麼動作!對呀,屬性是個什麼動作呢?那麼請有如此疑問的朋友仔細的考慮一下,是不是可以將屬性考慮爲GetXXX和 SetXXX的兩個方法,至於說字段怎麼怎麼地的某些兄弟俺就不多說了,回去自個好好想想吧,有些東西是屬於開發平臺爲我們做了很多的工作,只不過我們不 知道而已。
   好,問題到這裏已經有些眉目了,我們該討論如何使用“Act As”來對對象進行分類了。
   高手出招了,代碼如下:

 1 //可愛的小魚接口
 2 public interface IFish
 3 {
 4 }
 5 
 6 //可愛的爬樹接口
 7 public interface IClimbable
 8 {
 9 }
10 
11 //可以吃接口
12 public interface IEatable
13 {
14 }
15 
16 //彈塗魚出場了
17 //我要扮演魚
18 //我要扮演爬樹高手
19 //我要扮演可以吃的美味,貌似沒有人願意扮演這個
20 public class Goby : IFish, IClimbable, IEatable
21 {
22 }

    高手!請問我需要怎樣表演才能扮演成一條魚呢?高手愕然。
    看來我們的高手還是沒有擺脫“Is A”的荼毒呀!我們不要魚!我們要的是行爲!行爲由什麼決定的呢?由要用你這個類的地方期望要的行爲來決定的,例如我需要一個能夠提供游泳行爲的對象,你 就可以抽象"ISwimable"這個動作(這個單詞可能不對),然後尋求實現這個動作的對象就可以了(接口倒置原則)。
    有些朋友可能會有一些疑問,既然是動作,那麼動作之間怎麼會有繼承呢(接口的繼承)?例如:

1 //我是一個數據提供源
2 public interface IDataSource : IDisposable
3 {
4 }
5 

    仔細想想,這個是繼承嗎?是“Is A”嗎?不是!不知道大家玩過拳皇或者其它的格鬥遊戲沒有,要知道分別連續按鍵是可以組合出一個大招的,在某些情況下,對象的使用者或者理論一點的說法消 費者,需要是對象同時提供上述的兩種行爲,不過分吧。軟件設計的時候往往就是這個地方出問題,如果沒有分清楚的話,很有可能把本應該拆分的動作當作一套組 合拳給打了(接口隔離原則),這也是混亂的開始,重構的原因。
    我們一直以來都從“Is A”的角度來對對象進行歸類,但是仔細的想一想,“Is A”的標準是什麼?我們怎麼樣才能判定一個對象“Is A”另外一個對象呢?大家是不是基本靠猜測或者憑經驗在做?這也是軟件設計一直被當作是一種藝術行爲的原因。一下這個圖是我的一個觀點,請大家參考一下:

    其中箭頭表示對象的行爲,我們關注的行爲是指落在系統範圍之內的行爲,或者系統關心的行爲。
    好了,今天就寫到這裏吧,以後有時間我會再詳細的討論如何分拆動作,如何設計類的話題。

轉載地址:http://www.cnblogs.com/zengezenge/archive/2007/07/31/837860.html


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章