很多書上會寫著,對象是具有數(shù)據(jù)以及對這些數(shù)據(jù)提供的操作的集合。這是一個極其錯誤的認(rèn)識。這里的對象可以簡單理解為類似于現(xiàn)實生活中的對象,生活中是以對象為個體,并且不同對象間通過發(fā)送消息作為交流溝通方式。例如,社會的交換活動,任何人都是通過發(fā)送消息到另一個對象去請求其所提供的某種服務(wù)。整個面向?qū)ο笙到y(tǒng)就是以對象間的互相交互,協(xié)作形成的一個運行系統(tǒng)。 至于類,只是 同種性質(zhì)的對象的抽象體,是一個抽象概念,它只是用來讓編譯器認(rèn)識的。
每一個對象都提供某些服務(wù),當(dāng)然都是以方法的形式存在。而且,這些服務(wù)可能同時需要一些數(shù)據(jù)信息,這兩種即構(gòu)成了對象對外提供服務(wù)的基礎(chǔ)。也是最常見的。那種理解為先有數(shù)據(jù)信息,再由服務(wù)是不對的,否則,將難于進(jìn)行對象抽象以及設(shè)計。而且,這些方法不是專為數(shù)據(jù)服務(wù)或者說外界并不是為了訪問數(shù)據(jù),而時這些數(shù)據(jù)根據(jù)服務(wù)的需要決定需要什么數(shù)據(jù)信息以及如何暴露數(shù)據(jù)信息。與此相反的訪問方式,抽象數(shù)據(jù)結(jié)構(gòu)是個典型,這種方式以數(shù)據(jù)位中心,并不是面向?qū)ο蟮暮诵乃凇?面向?qū)ο蟮暮诵氖钦麄€世界的寫作過程,是以服務(wù)為基石,它并不是以數(shù)據(jù)位中心,而是以服務(wù)為中心,各對象通過接口暴露自己的服務(wù),為外界提供服務(wù)。這也是面向接口編程的主旨。所以面向?qū)ο髴?yīng)該是先有對象行為,而這些數(shù)據(jù)時反過來為這些行為提供數(shù)據(jù)基礎(chǔ)信息,為之提供數(shù)據(jù)服務(wù)的。這與傳統(tǒng)的ADT,數(shù)據(jù)+對數(shù)據(jù)的操作方法時截然不同的,盡管其結(jié)構(gòu)及其相似,它是方法依賴于數(shù)據(jù)。
基于這些原因,一個無數(shù)據(jù)的對象出現(xiàn)時很正常的,而且是占據(jù)很大部分。這些對象稱之為無狀態(tài)對象。即兩個同類對象,其行為時完全一樣的,因為已經(jīng)少了特定數(shù)據(jù)信息的依賴關(guān)系。現(xiàn)實生活中也確實存在這類只提供服務(wù)的對象,該對象提供的服務(wù)本身互相依賴,或同類,或是以某種一致的方式向外提供服務(wù)。而在面向?qū)ο蟮南到y(tǒng)中,這種無狀態(tài)服務(wù)對象是基于業(yè)務(wù)需求而定的。同樣的對象,在一種業(yè)務(wù)系統(tǒng)中,它是有狀態(tài)對象,需要某些依賴信息,而在另一個系統(tǒng)中,可能就以無狀態(tài)對象出現(xiàn),外界并不關(guān)注其數(shù)據(jù),而只是想獲取其服務(wù),這時這些數(shù)據(jù)信息并不存在意義,盡管它可以被保留住,對象里的服務(wù)于數(shù)據(jù),存在服務(wù)依賴于數(shù)據(jù),以及不依賴2種關(guān)系。然后,大部分是有依賴關(guān)系的,對于無狀態(tài)對象,有2種處理方式,其一,既然無狀態(tài),則可分布至各自不同的Util類中,如
class A {
sourt(..);
run(..);
study(..);
}
這里A的任何對象都是無狀態(tài)的對象,則應(yīng)放入不同Util類中并以static修飾它。這種無狀態(tài)類是不應(yīng)該被設(shè)計的,因為他充滿了大雜燴的壞味道。職責(zé)不明確,更不用提SRP了。并且給這種類取名也是一個大問題。再看,
class OrderService {
add(...);
remove(...);
update(...);
}
這個OrderService的一個實例,同樣時無狀態(tài)對象,然而這是一個合理的設(shè)計。因為其很好的吻合了對象的語義所在。提供了一組一致,互相合作,同類服務(wù)的服務(wù)方式。
有時會有很多對象,其提供服務(wù)時相同的,但是其具體實現(xiàn)的內(nèi)部細(xì)節(jié)不同,如:
基于class RemoteOrderService, class LocalOrderService所生成的對象,而且是很常見的,且其依賴的數(shù)據(jù)信息時不同的,這在生活中很存在的合理性。如
RunnerA {
run(...){
使用拖鞋跑
}
}
RunnerB {
run(...){
使用自行車跑
}
}
然而,我們無論創(chuàng)建RunnerA還是RunnerB的對象,我們都不關(guān)心其實現(xiàn)細(xì)節(jié),也就是我們根本不關(guān)心內(nèi)部數(shù)據(jù)的依賴細(xì)節(jié),我們只關(guān)心其為我們提供的服務(wù),它能使我從一個地方到達(dá)另一個地方。因而,其數(shù)據(jù)對我們而言是透明的。我根本不想知道,你是使用什么數(shù)據(jù),怎么run的。因而這種基于服務(wù)提供的方式,使得我們使用了一個只包含所提供服務(wù)的類型Runner。并且在我們看來,它隱藏了提供的服務(wù)的實現(xiàn)細(xì)節(jié),這就是接口。
interface Runner{
run(..);
}
而多態(tài)的性質(zhì),這時發(fā)揮了很好的作用。形成了一個種特殊的依賴關(guān)系,此時,client與Runner的依賴關(guān)系遠(yuǎn)遠(yuǎn)強(qiáng)于Runner與其實現(xiàn)類的依賴關(guān)系。這也就是面向?qū)ο髱状笤瓌t之一的DIP了。
因此,面向?qū)ο笙到y(tǒng)本質(zhì)是以接口為核心的系統(tǒng),每個接口就代替一個ServiceProvider, 然后,發(fā)送消息請求構(gòu)成了一個協(xié)作系統(tǒng)網(wǎng)。
而另一種極端,就是對象無行為。當(dāng)然,其是有狀態(tài)對象。這些對象都是不同的,盡管他們同屬一類。這種對象的出現(xiàn),使得面向?qū)ο蟮恼Z義受到了很大的沖擊。因為這種脫離了對象是以服務(wù)為核心的語義。一個對象沒了方法,那還談什么服務(wù)。然后,現(xiàn)實生活中的確是有些東西是無服務(wù)的,例如book, 而這種被稱為實體對象。這里并不是說該實體真的無服務(wù),而是其所提供的服務(wù)其實是無用的,或無意義的。因此,寧愿將其行為全部去除以保持其整潔,又不至于冗余。因為這同樣取決于業(yè)務(wù)系統(tǒng)的需求。這一種情形被稱為貧血模型,即不具行為之對象。不管貧血與否,其設(shè)計起源于業(yè)務(wù)系統(tǒng)的需求。設(shè)計是多種多樣的的,面向?qū)ο蟊旧硪髲膯栴}領(lǐng)域中提取對象是件難事,同時對象的職責(zé)分配更是一件難事。所以,出現(xiàn)了許多關(guān)于這方面的方法論,如CRC, 信息專家等職責(zé)分配方法以及大量面向?qū)ο笤O(shè)計原則,設(shè)計模式等等。因而,面向?qū)ο笤O(shè)計本身是一門高深的學(xué)問。并且取決于個人的經(jīng)驗以及知識面,處理業(yè)務(wù),分析,解決各種問題的思想,特別是基于某特定領(lǐng)域的業(yè)務(wù)經(jīng)驗。
我們發(fā)現(xiàn)了再生活中的不基于服務(wù)的,不基于消息發(fā)送請求服務(wù)的對象,我們僅僅能說這些對象不直接參與對象協(xié)作網(wǎng)。因為沒人能透過該網(wǎng)享受或請求到某種服務(wù)。但是,它是作為一種間接寫作者出現(xiàn),它作為其他對象間的請求服務(wù)的一種輔助,就好比交換系統(tǒng)中的物品,它是在服務(wù)對象間的請求鏈中流通,而流通過程中,沒有一個人會把請求發(fā)向該物品,他們可以持有它或流通它。當(dāng)然,有可能在流通中,稍微檢查物品是否合法等。而這時該物品也僅僅提供了合法檢查服務(wù)而已。跟基于對象服務(wù)的協(xié)作網(wǎng)是大小巫了。呵呵。
根據(jù)面向?qū)ο笤O(shè)計原則以及經(jīng)驗的權(quán)衡作出合理的設(shè)計時必需的。在這些不同的對象類型中,最容易被發(fā)現(xiàn)并提取的就是,貧血模型的對象。因為他直接反應(yīng)世界,不是只有程序員能想到,而是生活中的所有人都懂。這就是面向?qū)ο蟮暮锰帯T跇I(yè)務(wù)領(lǐng)域中,業(yè)務(wù)專家起到了相當(dāng)重要的作用。這就是面向?qū)ο蟮暮锰帯T跇I(yè)務(wù)領(lǐng)域中,業(yè)務(wù)專家起到了相當(dāng)重要的作用。如,圖書管理系統(tǒng),大家都會想到實體類,如book, student, library等等。這些就是不提供服務(wù)的對象。而且這些信息基本都會被持久化進(jìn)DB或其他地方,散發(fā)著某些DB的味道,因而這些對象一旦被冠以DB味道后,大多數(shù)人的初衷發(fā)生了微妙的變化,他們把設(shè)計的焦點轉(zhuǎn)向了DB,而遠(yuǎn)遠(yuǎn)脫離了他原本想做的基于面向?qū)ο蟮脑O(shè)計,久而久之,很多人習(xí)慣了基于DB的設(shè)計,一個系統(tǒng)一上來就開始建立表。把所以業(yè)務(wù)邏輯寄托在DB身上。所以,DB責(zé)任之大可想而知。因為面向?qū)ο笤O(shè)計與之相比是何等之難。這時候,所有的業(yè)務(wù)邏輯都依賴于DB,整個業(yè)務(wù)系統(tǒng)設(shè)計嚴(yán)重側(cè)向DB,一些以表為核心。從一個表能看出所有業(yè)務(wù),因為人們太習(xí)慣于關(guān)注信息了,而且DB是基于二維表的,從小學(xué)就學(xué)過,極其容易,管理層的家伙們很容易明白,這時管理層也參與了項目討論,很好。對著那些表,指著點著。這就是技術(shù)。