白馬非馬的面向對象分析
公孫龍,六國時辯士也。疾名實之散亂,因資材之所長,為“守白”之論。假物取譬,以“守白”辯,謂白馬為非馬也。以馬作為進行問題域進行建模,已知存在白馬這種類型。顯然存在馬的超類,并且馬類包含一個屬性-顏色,是否需要建立白馬的子類呢?顯而易見的是,當馬的顏色屬性是白色時,馬的一些實例表達了一個白馬的特殊實例群(由此我們可以得知:白馬顯然是馬),根據里氏替換原則,子類型必須能夠替換掉它們的基類型,顯然在分析了馬的行為模式以后,我們可以得出結論:白馬可以替換馬。----!難道真的要建立白馬、黑馬、X馬的子類嗎?
我認為可以從以下幾方面進行分析。
1、類的職責(很大程度上等同于服務能力,操作方式):
設計一個類,首先要從類職責的分析入手,一個類要承擔響應的職責,反過來說同樣的職責應該由同樣的類承擔,否則會造成類泛濫,實例孤單的狀況。如果領域內馬和白馬承擔同樣的職責,應該只建立馬一個類,不應該只見樹不見林,造成不抽象的類的產生。
2、類的行為模式(當類承擔響應職責時,如何擴展):
分析一個類要從類的行為模式入手,既然一個類要承擔責任,其承擔的責任表現方式是否一樣呢呢?這就是她的行為模式,這也是里氏替換原則主要起作用的地方,如果兩個類的職責相當,但行為模式不同則不能成為超類和子類的關系(比如"著名"的正方形不是長方形問題)。馬類,作為超類,基于一些特殊的行為方式:吃草,跑...,對于白馬她的行為模式和馬是一樣的,并沒有不同,所以白馬是馬而非馬的同根繼承子類。對于長方形和正方形都是具有相同計算面積算法(職責)的四方形的子類。
-------以下是關于此事的一些擴展分析-----------
3、子類的產生:
何時需要產生子類呢:是對其父類的職責進行擴展,白馬沒有對父類的職責進行擴展,所以不是馬的子類。首先子類要擴展超類,其次子類不能重寫或廢除超類的職責。
4、屬性,狀態的區別(類的域)
對于一些類,在狀態不同時,會有不同的表現(狀態機模式),所以,類的getter,setter的部分包含兩種不同的特性,對于屬于狀態的部分,是我們要仔細分析的,而"白"馬則屬于屬性類(非狀態)的域, 一般來講,一個類的實例要能提供相應的差異服務(由于狀態不同)最好使用不變模式[生存周期狀態不變]或狀態機[生存周期有狀態,但狀態不由調用者控制]來實現。
5、抽象類和接口
由于java的單根繼承特性,很多設計人員不敢定義抽象類為繼承樹根,一定要先定義馬的接口,在建立抽象馬,作為一種"準規范"無可厚非,但我認為這是不愿承擔責任的表現,有行為的基類應該可以(必須?)從類定義開始,避免白馬類(一旦馬成為接口,白馬的產生就更加"名正言順"了)的出現.將來如果發生變化可以通過重構(導出接口和使用委托),解決問題。
6、對象的創建(組裝)和使用應該分開
既然對象的狀態如此重要,屬性有有很大程度的不變性(白馬在構造時就用該是白的,并且一生不變),而騎馬的人不必要求馬的屬性(!),所以,我們應該將馬的構造和使用分開,使領域模型更清晰。使用一些Ioc容器,比如Spring就能很好的解決這些問題。
7、分析問題的領域
說了這么多,有一個問題;如果有一個馬的研究機構,專門對不同顏色的馬進行專題研究,馬的顏色可能會對馬的行為有很大影響,例如戰馬如果是黃色(綠色,哈哈)更利于偽裝,此時"白"可能是一個很關鍵的問題,顏色會影響到不同的偽裝策略,此時將白馬作為馬的一個子類則是必須的!所以問題域不同,類的設計就不同,生活中的問題域比較清晰(生物學家和廚師對馬的理解不同),而軟件建模時往往問題域混雜,這也是OO設計時比較困難的問題,所以分析問題域也是非常重要的設計問題。
posted on 2006-01-19 14:16 兼聽則明 閱讀(1062) 評論(4) 編輯 收藏 所屬分類: oo