實體
在對實體進行建模時,我們可能會把重點放在實體對象或者唯一標(biāo)識屬性的設(shè)計上猩谊,然而對于實體的本質(zhì)并沒有一個清晰的概念揪罕。這將導(dǎo)致你不知道什么是實體,還要將對象設(shè)計成實體的矛盾中吆鹤。最終可能會為一個模型對象添加一個唯一標(biāo)識(ID)屬性而宣布這個模型對象是個實體對象厨疙。
當(dāng)看到一個計算機領(lǐng)域中的概念,你可能會在意它在計算機領(lǐng)域中的解釋疑务。但有很多概念并不是計算機領(lǐng)域所創(chuàng)造的沾凄,它可能來源于其它領(lǐng)域。并且計算機領(lǐng)域可能對這個概念并沒有做過多的解釋知允,只是對概念的應(yīng)用撒蟀。
認(rèn)識實體
什么是實體? 當(dāng)突然被問到這個問題時温鸽,你想到了什么保屯?
一個在 E-R 圖中所表示的實體類型、一個具有唯一標(biāo)識的模型、一個被 @Entity
注解標(biāo)記的模型配椭、一個繼承自 Entity
類型的模型虫溜、或者把他們?nèi)诤显谝黄穑阂粋€具有唯一標(biāo)識的并且被 @Entity
注解標(biāo)記(或者繼承自 Entity
類型)的模型。
這些都只是技術(shù)抽象后的實體模型股缸,而并不是實體衡楞。那什么是實體呢?
An entity is something that exists separately from other things and has a clear identity of its own.
谷歌翻譯:實體是與其他事物分開存在的事物敦姻,并且具有自己的明確標(biāo)識瘾境。
拋開計算機領(lǐng)域?qū)δ闼伎忌系氖`,你是如何理解實體的呢镰惦?
形成實體
當(dāng)你帶著小朋友去動物園游玩迷守,你指著長頸鹿問小朋友:“這是什么動物呀?”旺入。小朋友會告訴你:“這是長頸鹿兑凿。”茵瘾。你繼續(xù)問他:“你怎么知道這是長頸鹿的礼华?”,小朋友又告訴你:“因為它的脖子很長拗秘,身上還有豹紋圣絮。”雕旨。你又繼續(xù)問:鴕鳥扮匠、河馬、獅子凡涩、猴子棒搜、大象、...活箕。
小朋友可以通過不同動物的特征來識別和區(qū)分動物帮非。人類的思想是可以表達這個世界的,這個可以被識別和區(qū)分其他事物的抽象概念被稱作:類型(Type)讹蘑。
類型的出現(xiàn)使得可以更好地表達如何區(qū)分事物,這對理解實體以及實體的出現(xiàn)又近了一步筑舅。
事物之間可以根據(jù)不同類型區(qū)分開來了座慰,比如:猴子(鴕鳥、河馬翠拣、獅子)類版仔。但是如何知道一群猴子里的某一只猴子呢?
小朋友來到小猴子的觀賞區(qū),指著一只小猴子說:“猴寶寶”蛮粮。過了一會那只猴寶寶跳到了一群猴寶寶群里益缎,小朋友此時已經(jīng)無法找到剛剛那只猴寶寶。
如果可以為每一只猴子分配一個唯一的編號然想,那么小朋友找到這只猴寶寶就變得十分簡單了莺奔。
如果小朋友能始終找到這只猴寶寶,那么這個猴寶寶就是一個實體变泄。
準(zhǔn)備好令哟,我們要開車了!
- 對事物的抽象建模稱之為實體類型妨蛹。
- 對實體類型的實例化稱之為實體屏富。
注意實例化的對象是有標(biāo)識的:
public class Monkey { // Monkey 是一個實體類型。
public static void main(String[] args) {
Monkey monkey1 = new Monkey(); // monkey1 是一個實體蛙卤。
Monkey monkey2 = new Monkey(); // monkey2 也是一個實體狠半。
System.out.println(monkey1 == monkey2); // false
}
}
但是非常抱歉的是,我們對事物的認(rèn)識遠遠沒有那么清晰颤难。
public class MonkeyService { // MonkeyService 是一個類(class)神年。
public static void main(String[] args) {
MonkeyService service1 = new MonkeyService(); // service1 是一個對象(object)。
MonkeyService service2 = new MonkeyService(); // service2 也是一個對象(object)乐严。
}
}
應(yīng)用邏輯服務(wù)(MonkeyService)是一個實體類嗎瘤袖?它顯然不是,因為它只是對業(yè)務(wù)規(guī)則的封裝昂验,而不是對事物的抽象捂敌。他的作用是在執(zhí)行期間訪問各種實體對象來組合業(yè)務(wù)規(guī)則。
只有對事物的抽象才稱之為實體既琴。
我們曾經(jīng)花了很長時間來理解透徹 類(class) 和 對象(object) 之間的關(guān)系占婉。
- MonkeyService 叫做對象類。
- service1, service2 叫做對象甫恩。
我們從來沒有指著 MonkeyService
這個東西叫對象逆济,service1, service2
這個東西叫類。
正是這樣的關(guān)系磺箕,我們對事物建模形成的類稱之為實體類奖慌,通過實例化(new
)實體類而產(chǎn)生的對象實例稱之為實體。
我喜歡稱它們?yōu)?strong>實體對象松靡,因為它們也是個對象简僧。
我還是擔(dān)心,你沒有明白我這么啰嗦的表達什么是實體雕欺。我決定從另一個角度在探討一次什么是實體岛马。
再次強調(diào)一下:對事物的建模稱之為實體類型棉姐。
我們反反復(fù)復(fù)的強調(diào),對事物的建模就稱之為對實體的建模啦逆,那什么是事物伞矩?什么不是事物呢?
實體(Entity)可以是一個人夏志、一座城市乃坤、一輛汽車、一張彩票或一次交易盲镶。
我們會使用各種名詞來代表事物侥袜,比如人、城市溉贿、汽車枫吧、彩票、交易宇色。因此我們會有一種錯覺九杂,對實體的建模就是對名詞的建模。然而是這樣嗎宣蠕?
我們在創(chuàng)造一個名詞時例隆,并不是先創(chuàng)造一個名詞然后在指向一種事物。而是存在一種事物,然后在為它創(chuàng)造一個名詞。
比如你看到一頭豬(動物)嘉汰,你會說:“我看到了一頭豬(名詞)”。但是這頭豬(動物)在沒有名詞(豬)的時候就已經(jīng)存在了唱逢,在描述沒有名詞的事物時,你可能會“阿巴阿巴阿巴”的敘述一堆對這個事物的描述屋休。但它卻是存在啊坞古,你是通過它所具有的 特質(zhì)(屬性) 來區(qū)分這是一頭豬不是一頭驢的。
在認(rèn)識事物的時候劫樟,你是通過屬性來區(qū)分不同事物的痪枫,而不是最終表現(xiàn)的名詞。
事物看起來確實是由這些屬性所構(gòu)成的叠艳,那它是由這些屬性來確定唯一性的嗎奶陈?
實體標(biāo)識
- A:你說的哪一頭豬啊附较?
- B:就是那一頭澳虿t。?/li>
- A:那是哪一頭翅睛?
- B:非常胖的那一頭声搁!
- A:到底哪一頭?
- B:滾捕发,算了疏旨。
那這頭沒有顯式編號(標(biāo)識)的豬還是不是一個實體呢?
當(dāng)然是扎酷,它必須是檐涝。只是你還不知道如何唯一標(biāo)識它。如果此時你說:“那頭編號為 5 的豬法挨∷瘢”,這將在描述實體時變得如此簡單凡纳,因為 A 和 B 都知道 5 號豬是哪一個窃植。就算是不知道,只需要去豬圈里找到 5 號豬即可荐糜。
一個事物從產(chǎn)生巷怜,發(fā)展,興盛直至消亡的過程中暴氏,它們的形式和內(nèi)容可能一直在發(fā)生變化(有可能是根本性的變化)延塑。在經(jīng)歷這個“成住壞空”的過程中什么是不變的呢?
一個人剛出生時可能只有五六斤那么重答渔,成年以后可能會長到一百三四十斤关带。剛出生時可能只有四五十厘米那么高,成年以后可能會長到一米七八那么高沼撕。剛出生時小臉可能有一些紅暈宋雏,成年以后可能會變得俊美。
在這一生中端朵,你的體型好芭、身高、相貌和年齡都在發(fā)生變化冲呢,甚至姓名都可能會改變舍败。是什么使你在這茫茫人海中能夠獨立存在,并且別人能夠認(rèn)出你是誰敬拓。甚至在公司里有兩個重名的同事邻薯,你依然可以分辨他們誰是誰。但是你在通過名字分辨他們時乘凸,你腦海里是關(guān)聯(lián)的那個人本身厕诡。他就是他,是不會變得营勤。不管他的體型灵嫌、身高壹罚、相貌和年齡發(fā)生任何根本變化,你依然能識別他寿羞,因為他就是他猖凛。
人類需要解決他就是他的這個問題,標(biāo)識就是為了解決他就是他的這個問題绪穆。人類的思考就是這么強悍辨泳。
事物本身是具有標(biāo)識的,只是我們還沒有找到如何發(fā)現(xiàn)標(biāo)識的密碼玖院。但是我們知道標(biāo)識是存在的菠红,又無法發(fā)現(xiàn)它時,我們只好給它為事物自定義一個標(biāo)識难菌。
通常標(biāo)識是不變的试溯,它會伴隨一個事物的一生。正是這種不變性與唯一性才能貫穿一個事物在整個生命周期中抽象的連續(xù)性扔傅。
注意: 在對象模型中耍共,標(biāo)識是通過字段(屬性)的方式進行實現(xiàn)的(表示的),定義一個標(biāo)識有時只需要一個字段就夠了猎塞,但有時一個字段往往不能唯一標(biāo)識一個實體试读,此時我們可能會使用兩個、三個甚至四個字段來明確實體的唯一性荠耽,我們把這種多個字段組合成的標(biāo)識叫做復(fù)合標(biāo)識或者聯(lián)合標(biāo)識钩骇。
實體必須定義標(biāo)識嗎?
實體必須是有標(biāo)識的铝量,但是你不一定需要為每一個事物建模時都定義標(biāo)識倘屹。
當(dāng)你在商場購買一件衣服時,你會在意一件衣服的標(biāo)識嗎慢叨?你只會在意它的品牌纽匙、尺碼、顏色拍谐、款式等等一系列的屬性烛缔,此時商品標(biāo)識顯得就沒有那么重要了,商品標(biāo)識更像是這件衣服的附帶品(附加值)轩拨。過了幾天你又去了這家商場践瓷,這次不是買,而是換貨亡蓉。前臺服務(wù)員讓你提供當(dāng)時夠買衣服時的小票晕翠,服務(wù)員根據(jù)小票的標(biāo)識查詢到你購買的衣服,最終為你了換貨砍濒。
在為小票建模時淋肾,小票上的商品標(biāo)識就無法確定唯一性了硫麻,因為多張小票可以關(guān)聯(lián)同一個商品(多對多)。然而這個商品在這一張小票上卻是唯一的樊卓,我們可以通過(ReceiptId庶香、ProductId)來定位這個購買的商品。但是我們從不關(guān)心小票上的商品脫離小票后是否唯一简识。
小票上的商品是實體嗎?
我們在認(rèn)識實體時特別強調(diào)了實體的概念:
實體是與其他事物分開存在的事物感猛,并且具有自己的明確標(biāo)識七扰。
為一個事物定義了明確的標(biāo)識后,會使你有一種錯覺陪白。你會感覺只要為事物定義明確標(biāo)識后颈走,事物就是實體或者實體就是事物了。
但是我們對分開存在的理解還需要強化咱士。
分開存在就意味著需要獨立存在立由,小票上的商品對象(Receipt Product)離開小票對象(Receipt)能獨立存在嗎?
- 如果能序厉,商品對象(Receipt Product)就是一個實體锐膜。
- 如果不能,商品對象(Receipt Product)就不是一個實體弛房。
如果商品對象(Receipt Product)不是實體道盏,那它是什么?
是對象(Object)啊文捶,這樣的回答你是否能想明白(阿巴阿巴阿巴)荷逞。我們一直叫實體為實體對象,是因為實體本身就是一個對象啊粹排。不是因為面向?qū)ο蟛沤兴鼘ο笾衷叮撬褪菍ο蟛沤兴鼘ο蟆ο笸缍嶓w的概念要比計算機對面向?qū)ο?/strong>的應(yīng)用早的多得多坠敷。
對象要比實體的范圍大的多得多,對象包括(實體)斧抱,實體對象只是對實體的抽象常拓,對象比實體抽象的“東西”多得多的。
建模:實體與值對象辉浦,做出選擇弄抬。
“我們應(yīng)該盡量使用值對象來建模而不是實體對象”,我在看到這句話時宪郊,確實驚訝不已掂恕。
阿巴阿巴阿巴拖陆,去做選擇吧。
實體行為
對象是由屬性和方法組成懊亡。
我們都在試圖理解這句話依啰,有的時候卻一直在相半而行。
過去我們的對象上只包含屬性店枣,后來我們意識到這樣是不完整的速警。然后我們開始為對象抽象方法,添加方法鸯两。但是這個過程卻發(fā)生了極化闷旧,有一部分人提出只能使用方法來操作對象。
這個過程最終產(chǎn)生了三種方式來操作對象:
- 只使用屬性來操作對象钧唐。
- 使用屬性和方法來操作對象忙灼。
- 只使用方法來操作對象。
這三種方式到底哪個合理呢钝侠?
在《Java 編程思想》中有一個使用電燈(Light)的例子來初次解釋什么是面向?qū)ο蟆?/p>
這個例子為我們展現(xiàn)了電燈對象所具有的行為:開燈(On)该园、關(guān)燈(Off)、變亮(Brighten)帅韧、變暗(Dim)里初,這些行為是本身所具有的。
到目前為止這個例子好像確實是只使用方法來操作對象弱匪。
如果現(xiàn)在要求可以任意調(diào)整電燈的顏色(Color)青瀑,應(yīng)該怎么設(shè)計了呢?
顏色(Color)是一個屬性(Property)萧诫,需要改變電燈的顏色斥难。我們瞬間想要為電燈對象提供一個改變顏色(Change Color)的方法。
真的需要為電燈對象提供一個改變顏色(Change Color)的方法嗎帘饶?
不一定需要哑诊,直接修改屬性(Property)是可以的。
你知道屬性(Property)和字段(Field)的區(qū)別及刻?
屬性(Property)具有封裝性镀裤。
有一天你感覺那面墻的顏色有些不好看,你拿著刷子就去刷墻缴饭。墻也沒有為你提供一個改變顏色的方法暑劝,而你卻直接改變了墻的顏色屬性。
這個方法屬于這個對象嗎颗搂?
我曾經(jīng)看到過一個視頻:外國人用白瓷盤切烤制好的乳豬担猛,完成切割后隨手拋出瓷盤摔壞。
你覺得摔壞這個動作屬于盤子對象嗎?如果屬于:
public interface Plate {
void crash(); // break 摔壞
}
這就好比傅联,你對這一個盤子告訴它先改,你摔壞自己。盤子本身明顯是不具備自我摔壞這樣的功能的蒸走,盤子之所以會被摔壞是外界對它的摧殘仇奶。對于實體對象,本身方法應(yīng)該是對事物本身所具有功能的抽象比驻。
由于在 Java 中不能直接創(chuàng)建函數(shù)(function)该溯,所以你只能這樣:
public class Crasher {
public void crash(Plate plate) {
// 摔壞它...
plate.broken(); // 已摔壞
}
}
開源電商
Mallfoundry 是一個完全開源的使用 Spring Boot 開發(fā)的多商戶電商平臺。它可以嵌入到已有的 Java 程序中别惦,或者作為服務(wù)器朗伶、集群、云中的服務(wù)運行步咪。
- 領(lǐng)域模型采用領(lǐng)域驅(qū)動設(shè)計(DDD)、接口化以及面向?qū)ο笤O(shè)計益楼。
項目地址:https://gitee.com/mallfoundry/mall
總結(jié)
我們從認(rèn)識實體中了解到了實體的概念猾漫。并在形成實體中去引出事物與實體的關(guān)系,實體類與實體的關(guān)系感凤,類與對象的關(guān)系悯周,以及實體與對象的關(guān)系。又在實體標(biāo)識中強調(diào)了標(biāo)識對實體的重要性陪竿,以及由強調(diào)了實體與對象的關(guān)系禽翼。最后又加入了一點對實體行為的擴展,對實體本身的屬性和方法做了一點點的探討族跛。
請記住這句話:實體是與其他事物分開存在的事物闰挡,并且具有自己的明確標(biāo)識。