實體和值對象
實體和對象
故常無欲以觀其妙,常有欲以觀其徼
初始實體和演化實體
代碼中的DTO
AutoMapper實體轉換
後記
實體(Entity)、對象(Object)、DTO(Data Transfer Object)資料傳輸對象,老生常談話題,簡單的概念,換個角度你會發現更多的東西。個人拙見,勿喜請噴。
在正常開發中(事務腳本),我們所說的實體隻是一些資料庫映射的字段,對象隻不過是包含業務功能描述的集合而已,在DDD(領域驅動設計)中,實體(Entity)和值對象(Value Object)是基本元素之一,事務腳本中所說的對象概念大概就是領域模型中領域(Domain)的概念了,但并不是隻是業務功能描述的集合而已,不針對功能實作,而是針對業務協作完成的一種流程,DDD中的實體是一種領域對象,差別實體和值對象的方法就是判斷是否有唯一标示,而不是屬性,即使屬性完全相同也可能是兩個不同的對象。同時實體本身有狀态的,而且有自己的生命周期,實體本身會展現出相關的業務行為,業務行為會對實體屬性或狀态造成影響和改變。比如雙胞胎假設所有的屬性都一樣,仍然是兩個不同的人。從哲學角度講,這正是實體的本來含義。它是除了所有屬性之外還不足以表達的“那個”東西,不依賴其它而自存的東西。
如何區分實體和值對象,比如在城市社保系統中,參與社保人就是一個實體,在業務系統中,社保是一種概念,針對的是參與社保人,是以我們要在業務中來區分參與社保人,人有可能同名同姓,是以不能用名字來區分,這裡的名字就是參與社保人的一個屬性,是以我們用身份證号來區分參與社保人,這裡的身份證号就是參與社保人的唯一标示,用來說明:實體是什麼?實體是哪個?
還有有一種業務場景是這樣,比如在全國社保統計系統中,統計各個城市的參與社保的比率,因為我們隻要知道這個人是不是參與了城市社保?而并不需要知道他是哪個人,是以這裡面的參與社保人就是一個值對象,隻是用來說明:值對象是什麼?
可以看出區分實體和值對象隻是在特定的業務場景下,同一種特定對象可能會有不同的方式看待,這裡面就是一個邊界的問題,而且特定的業務場景中的實體是有自己的狀态和生命周期,這和值對象也有明顯的區分。
道可道,非常道。名可名,非常名。 無名天地之始,有名萬物之母。故常無欲以觀其妙; 常有欲以觀其徼(jiào)。 此兩者同出而異名,同謂之玄,玄之又玄,衆妙之門。 --《道德經》
上面這段話出自老子的道德經的開篇,簡單說下前兩段話的意思:道似乎有具體的定義,但總不是我們所想象出的定義,名取出了一個名,但不一定我們會一直使用。下面幾段就是對有(名)和無(道)的辯證關系,最後得出:“無”是天地的來處,“有”是衍生萬物的結果,這兩者之間,同出為意義不一樣,同樣好似玄妙務必,無窮無盡,切是研究一切的門經。
為什麼會引用道德經?其實在我看來,老子不做軟體開發真是太虧了(哈哈),什麼是實體和對象?可能每個人都有自己的解讀,就像上面讨論的實體和值對象,其實某種意義上來說應該是領域對象和對象屬性,這裡說對象屬性也并不是準确,就比如項目中我們使用的屬性字典,并不是任何一種對象的屬性,隻是一個特定的值,不依附于任何對象。實體雖然稱作實體,其實是一個對象,值對象雖然稱作對象,但其實隻是一個特定值,意義就像”道可道,非常道,名可名,非常名“一樣,
老子探讨的有無關系,其實在軟體程式設計中就是實體和對象的關系,“有”可以看做是“實體”,“無”可以看做是“對象”,無衍生出有,有展現出無,就像實體和對象之間的關系,實體是不是對象?對象是不是實體?實體和對象到底什麼?這其實隻是存在一個邊界問題。正如DDD中,實體即是領域對象,對象即是實體模型,我們生活中常常讨論:“是先有的雞蛋?還是先有的雞?”最後都沒有得出一個準确的結果,如果老子來回答這個問題,就六個字:“雞生蛋,蛋生雞”,至于解釋,老子揮一揮衣袖,騎上青牛遠去-“自己去琢磨吧”。
故常無欲以觀其妙,常有欲以觀其徼(jiào)。 --《道德經》
這段話我覺得是道德經開篇的精髓,你可能從字面上可以體會得到一些内容,這其實一種态度,一種生活态度,一種程式設計态度。
“故常無欲以觀其妙”,這句話在我們的現實生活中可以很好的去解讀,世間萬物是如此的大,我們還有很多的事物沒有去認知,是以我們就會抱着征服的欲望去探尋,看到美好的事物就想去掠奪占有,就像當你偶然發現一朵非常漂亮的鮮花,很多人不會停留下去欣賞它,而是去采摘它,然後據為己有,生活中的例子比比皆是,就像文章會犯錯一樣。
老子的所提倡的就是我們應該保持“無欲”的心态去看待事件萬物,去觀察,去體會它的玄妙,上面所說的掠奪、占有,就不是“觀”所蘊含的意義了。我們在做項目中,項目前期需求還沒有确定好就去開發,到最後弄得進退兩難,在DDD中,業務需求是很重要的一環,我們應該花更多的時間去了解它、體會它、确定它,而不是想當然的了解後就去開發項目,這也是模組化專家所必備的基本條件。
“常有欲以觀其徼”,這句話的中的精髓就一個字“徼”,徼翻譯為邊界的意思,“有欲”在現實生活中可以指一些有名望、有地位、有财富的人,這些人當擁有了一些常人所不能擁有的東西後,并不懂得收斂和滿足,反而使自己的欲望心更大,想得到更大的滿足,得到後還想得到,沒有一個界限,最後的下場一般都是很慘,就像和珅貪得無厭一樣。
老子所提倡的就是我們在“有欲”之後,要觀察、體會一個界限,要使自己的“欲”控制在這個界限中,水滿則溢就是這個道理。就像在DDD中,實體和值對象邊界的确定一樣。
含德之厚,比于赤子。
專氣緻柔,能如嬰兒乎?
為天下豁,常德不離,複歸于嬰兒。
--《道德經》
老子在道德經中多次提到有關嬰兒的話題,就像上面幾句,總是拿一些事物和嬰兒進行比較,難道說老子喜歡嬰兒?準确的應該說,老子推崇嬰兒的那種狀态,何種狀态?無欲無求、回歸自然、保持天性。。。

人的進化史進行了千百萬年,從最初的簡單生存原則,發展到現在複雜的人世關系,越進化越複雜,導緻我們現在越活越累。新出生的嬰兒沒有任何外界的摻雜,是如此的純淨,正如一碗清水一般,但随着成長,慢慢的接觸外界事物,清水也會被染成五顔六色,而失去了本來固有的一些東西,這也就是為什麼老子推崇嬰兒的原因。有時候我們離開喧嚣的城市,置身于甯靜的山坳,你會發現身心是如此的舒暢,其實這才是我們所固有的東西,隻是處在亂世中,把那一抹清明掩蓋罷了。
什麼是初始實體和演化實體?這隻不過是我自己定義的,這裡面的實體也可以看做是對象,隻是在DDD中稱作為實體,如上面所說,嬰兒就像初始實體一樣,長大後的我們就是演化實體,初始實體隻有一種狀态,也就是一種原始狀态或者稱作是無狀态,特定的場景下初始實體隻有一個抽象出來的對象,但是演化實體有很多種,但都是從初始實體演化出來的,是以稱為演化實體,有直接的關系也有間接的關系,如果把嬰兒看做是初始實體,長大後的我們是演化實體,但演化實體并不隻有長大後我們,汽車、成績單、衣服等等一些與我們相關的事物都可以稱為演化實體,但長大後的我們隻是和初始實體有直接關系,其他的和初始實體都是間接關系,這個特定的場景就是人類進化史。
當然有人看到這可能有些想法,認為你這說的什麼亂七八糟的東西,沒有一點實際的意義。我的意思并不是說明初始實體和演化實體是個什麼東西,而是說在我們做項目的過程中要找到那個“初始實體”,比如物流業務系統場景,在這個系統中哪個是初始實體?排程?賬單?掃描?都不是,準确的說應該是運單,因為所有的業務操作都是圍繞它來展開,或者是由它演生而來,雖然初始實體我們找到了,但是要仔細的揣摩它,确定是出生的嬰兒還是長大後的我們?
聚合(Aggregate)和聚合根(Aggregate Root)是DDD中的重要概念,什麼是聚合?它通過定義對象之間清晰的所屬關系和邊界來實作領域模型的内聚,并避免了錯綜複雜的難以維護的對象關系網的形成,聚合定義了一組具有内聚關系的相關對象的集合,我們把聚合看作是一個修改資料的單元。如果把人類社會看做是領域模型,聚合看做是一個國家,國家中的人是一個實體,那這個國家的人就是一個聚合根,但是每個國家的人都是人,隻不過膚色、語言、習俗會有些不同,可以把人看做這個場景中的初始實體,也就是初始聚合根,而不是國家的人。
DTO(Data Transfer Object)資料傳輸對象,注意關鍵字“資料”兩個字,并不是對象傳輸對象(Object Transfer Object),是以隻是傳輸資料,并不包含領域業務處理,雖然用途隻是傳輸資料,但本身其實也是對象,完成與領域對象之間的轉換,就像上面說的值對象一樣,某種意義上DTO可以看做是值對象的集合,隻不過是和領域對象之間的映射,不包含任何的業務邏輯。
為什麼要使用DTO?主要原因是隔離Domain Model,使改動領域模型而不影響UI,還有就是保持領域模型的安全,不暴露業務邏輯。還有就是在分布式模式下,不同的場景使用相同的資料結構有不同的需求,而我們又不得不做一些資料轉化,這是很繁瑣的,如果我們在項目初期,做DTO的分析,這樣我們就會省很多的事,而且還不會影響整個項目的業務流程,也友善以後對項目進行擴充。
下面我們虛拟一個簡單“文章”領域模型:
文章領域模型對應DTO:
從上面ArticleDTO中可以看到多了兩個屬性:Summary(文章摘要)和PostYear(文章發表年份),這就是我們在特定的業務場景中需要的,并不會影響到領域模型,如何實作領域模型和DTO之間的轉換?我們可以使用AutoMapper可以很友善的對他們進行轉換,一個強大的Object-Object Mapping工具。
工具-庫程式包管理器-程式包管理控制平台,輸入“Install-Package AutoMapper”指令,就可以把AutoMapper添加到項目中,有關AutoMapper相關文檔可以參考:https://github.com/AutoMapper/AutoMapper/wiki,這邊簡單示範下Article到ArticleDTO之間的轉換。
轉換效果:
其實這篇文章原本隻是想簡單寫下DTO及AutoMapper的用法,但是不知怎的寫着寫着就寫跑偏了,現在回過頭看也不知道自己寫了些什麼東西,正如張三豐教張無忌太極劍法,問他記得了多少,最後什麼都沒記得。
随着DDD(領域驅動設計)的學習和對道德經的感悟,就會發覺:此兩者同出而異名,同謂之玄,玄之又玄,衆妙之門。
如果你覺得本篇文章對你有所幫助,請點選右下部“推薦”,^_^
參考資料:
http://www.cnblogs.com/dudu/archive/2011/12/16/2284828.html
http://www.cnblogs.com/ego/archive/2009/05/13/1456363.html
http://www.cnblogs.com/jiguixin/archive/2011/09/19/2181521.html
http://blog.csdn.net/yujunwu2525/article/details/7850486
作者:田園裡的蟋蟀
微信公衆号:你好架構
出處:http://www.cnblogs.com/xishuai/
公衆号會不定時的分享有關架構的方方面面,包含并不局限于:Microservices(微服務)、Service Mesh(服務網格)、DDD/TDD、Spring Cloud、Dubbo、Service Fabric、Linkerd、Envoy、Istio、Conduit、Kubernetes、Docker、MacOS/Linux、Java、.NET Core/ASP.NET Core、Redis、RabbitMQ、MongoDB、GitLab、CI/CD(持續內建/持續部署)、DevOps等等。
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接。
分享到:
QQ空間
新浪微網誌
騰訊微網誌
微信
更多