面向對象編程的誤解
我覺得大多數程序員都理解錯了。這里的大多數不限於Java程序員,而是指使用面向對象編程語言的大多數程序員。本人就是其中一個。
最根本的原因在於,我們把面向對象里的“對象”理解錯了,我們理解成了語法層面的對象。所以我們的代碼才會出現所謂的貧血模型。
面向對象編程里的“對象”是什么?
封裝了數據和行為的東西
我們的代碼有體現嗎?
沒有。語法層面對象的3大特點(封裝、繼承、多態),我們的代碼都有體現。
但是對象里要么是只有數據,沒有行為(POJO)。要么是只有行為,沒有數據(Serivce)。即所謂的貧血模型。
定義POJO,封裝了屬性和getter&setter,看似具有封裝性,其實僅僅是一個數據容器而已。因為沒有把數據和行為封裝起來,行為都放在Service里了。
這就是我說的語法層面的面向對象。正式的叫法是面向數據編程。
真正的面向對象,面向的是生活中的真實對象,用代碼的方式模擬真實的對象,即我們說的模型:
比如我們要模擬貓這個現實中的對象。我們了解到貓有品種、顏色、體重等屬性;貓有吃魚、捕鼠的行為。
那么首先對它進行建模。這個模型要能如實的反應貓的特點,並且這個模型是穩定的,一旦定了不能隨意修改,比如隨便的將“捕鼠”這個行為拿掉。
注意這里說的是模型,該模型里有數據,有行為。真正用代碼實現模型的是不一定只有一個類。可能有很多個類:聚合根,實體,值對象,域服務等。
這些類合起來稱作模型!
注意這個點,這些類合起來稱作模型!雖然有些類可能只有行為,沒有數據(比如域服務),但這不能稱作貧血。因為貧血指的是模型,而不是單個類。
網上有很多關於貧血的討論,有些說法已經跑偏了,他們認為只要某個類沒有同時具備數據和行為就是貧血的。或者實體里沒有實現持久化就是貧血的。
這種看法是短視的。站在模型的角度從上往下看,實體,值對象,域服務,(實現持久化的)在一個模塊里緊密聯系,協同合作,就相當於封裝了數據和行為,
這就不貧血了。
理解了上述的“面向數據”和“貧血”這2個概念,才算是領悟到了“面向對象”的真諦。