本文列出了我在平時(shí)發(fā)現(xiàn)和積累的在面向?qū)ο缶幊讨幸恍┏R姷?ldquo;不夠面向?qū)ο?rdquo;的情況。
需要指出兩點(diǎn):
1.我們雖然列出了這九種情況,但并不是說(shuō)出現(xiàn)了下面的情況就一定有問(wèn)題了;我們希望讀者這可以將其作為一種信號(hào)——仔細(xì)考慮一下是不是有更好的設(shè)計(jì)。
2.我們這里所說(shuō)的面向?qū)ο蟮膶?duì)象特指領(lǐng)域?qū)ο螅磳?duì)象中包含領(lǐng)域數(shù)據(jù)和業(yè)務(wù)邏輯。
要確定不夠面向?qū)ο蟮膶?duì)象,首先要了解什么樣的對(duì)象算是面向?qū)ο蟮模蛘哒f(shuō)好的面向?qū)ο蟮膶?duì)象。關(guān)于面向?qū)ο笤O(shè)計(jì)的原則從不同的角度有很多種說(shuō)法,我們這里采用一種比較簡(jiǎn)單的說(shuō)法,即高內(nèi)聚低耦合。所謂高內(nèi)聚是指對(duì)象內(nèi)的數(shù)據(jù)和方法是緊密相關(guān)的;所謂低耦合是指對(duì)象之間的依賴應(yīng)當(dāng)比較小,一個(gè)對(duì)象發(fā)生改變時(shí)不應(yīng)當(dāng)對(duì)不相關(guān)的對(duì)象產(chǎn)生影響。
一. 低內(nèi)聚對(duì)象
我們把低內(nèi)聚對(duì)象分為兩種:一種是應(yīng)該屬于該對(duì)象的行為和數(shù)據(jù)分散到了其他對(duì)象中;另一種是該對(duì)象內(nèi)部的行為和數(shù)據(jù)關(guān)系不夠緊密。下面的1、2是屬于前一種情況,3、4、5則是屬于后一種情況。
1.貧血對(duì)象(Anemic Object)
瞧,那條貧血的狗!
故事的發(fā)生是這樣的...
你養(yǎng)了一條寵物狗,在學(xué)習(xí)了面向?qū)ο缶幊讨螅愦蛩銥檫@條狗設(shè)計(jì)一個(gè)面向?qū)ο蟮南到y(tǒng)。于是,根據(jù)你在C語(yǔ)言編程時(shí)的開發(fā)經(jīng)驗(yàn),結(jié)合你對(duì)“封裝”二字的理解,你設(shè)計(jì)了這樣一條狗:)這條狗由四部分組成:頭、身子、腿和尾巴。
圖 1
隔壁住著一位面向?qū)ο蟠髱?mdash;—法號(hào)鑒摩,你拿著設(shè)計(jì)圖給他看。鑒摩大師只掃了一眼便說(shuō):
沒有行為的對(duì)象不是好對(duì)象。
你似懂非懂地點(diǎn)了點(diǎn)頭,正要往下說(shuō),大師揮了揮手說(shuō):“你明天再來(lái)罷。”
如果一個(gè)對(duì)象只有數(shù)據(jù)沒有行為,它就是一個(gè)貧血對(duì)象,它只能被別人操作,或者作為某個(gè)操作的結(jié)果。對(duì)于簡(jiǎn)單的getter和setter,我們一般不將其歸為領(lǐng)域行為。所以,上面這個(gè)對(duì)象就是一個(gè)貧血對(duì)象。這條狗還不會(huì)叫、不會(huì)跑,甚至還不會(huì)搖尾巴討好你,真不知道你養(yǎng)這樣一條狗干啥。
處理貧血對(duì)象時(shí)可以考慮把操作對(duì)象數(shù)據(jù)的行為移動(dòng)到這個(gè)對(duì)象里面。對(duì)數(shù)據(jù)的封裝只是面向?qū)ο笾?ldquo;封裝”這個(gè)概念的一部分,我們的對(duì)象中除了封裝數(shù)據(jù)還應(yīng)當(dāng)封裝行為。
對(duì)于跟物理世界一一對(duì)應(yīng)的對(duì)象,一般來(lái)說(shuō),我們不容易犯這樣的錯(cuò)誤。我們不妨來(lái)看一個(gè)實(shí)際工作中遇到的例子。在某個(gè)商店收銀系統(tǒng)中,有一個(gè)對(duì)象叫做Product,它被設(shè)計(jì)成這樣:
圖 2
這個(gè)Product就是一個(gè)貧血類。單純看這個(gè)類,是沒有什么問(wèn)題的。我們需要結(jié)合其他的類來(lái)觀察。由于不同類型的產(chǎn)品打印方式不同,計(jì)稅規(guī)則也不同,所以我們還有一個(gè)處理Product的類: