實體(Entity)、對象(Object)、DTO(Data Transfer Object)數據傳輸對象,老生常談話題,簡單的概念,換個角度你會發現更多的東西。我的拙見,勿喜請噴。html
在常規開發中(事務腳本),咱們所說的實體只是一些數據庫映射的字段,對象只不過是包含業務功能描述的集合而已,在DDD(領域驅動設計)中,實體(Entity)和值對象(Value Object)是基本元素之一,事務腳本中所說的對象概念大概就是領域模型中領域(Domain)的概念了,但並非只是業務功能描述的集合而已,不針對功能實現,而是針對業務協做完成的一種流程,DDD中的實體是一種領域對象,區別實體和值對象的方法就是判斷是否有惟一標示,而不是屬性,即便屬性徹底相同也多是兩個不一樣的對象。同時實體自己有狀態的,並且有本身的生命週期,實體自己會體現出相關的業務行爲,業務行爲會對實體屬性或狀態形成影響和改變。好比雙胞胎假設全部的屬性都同樣,仍然是兩個不一樣的人。從哲學角度講,這正是實體的原本含義。它是除了全部屬性以外還不足以表達的「那個」東西,不依賴其它而自存的東西。git
如何區分實體和值對象,好比在城市社保系統中,參與社保人就是一個實體,在業務系統中,社保是一種概念,針對的是參與社保人,因此咱們要在業務中來區分參與社保人,人有可能同名同姓,因此不能用名字來區分,這裏的名字就是參與社保人的一個屬性,因此咱們用身份證號來區分參與社保人,這裏的身份證號就是參與社保人的惟一標示,用來講明:實體是什麼?實體是哪一個?github
還有有一種業務場景是這樣,好比在全國社保統計系統中,統計各個城市的參與社保的比率,由於咱們只要知道這我的是否是參與了城市社保?而並不須要知道他是哪一個人,因此這裏面的參與社保人就是一個值對象,只是用來講明:值對象是什麼?數據庫
能夠看出區分實體和值對象只是在特定的業務場景下,同一種特定對象可能會有不一樣的方式看待,這裏面就是一個邊界的問題,並且特定的業務場景中的實體是有本身的狀態和生命週期,這和值對象也有明顯的區分。編程
道可道,很是道。名可名,很是名。 無名天地之始,有名萬物之母。故常無慾以觀其妙; 常有欲以觀其徼(jiào)。 此二者同出而異名,同謂之玄,玄之又玄,衆妙之門。 --《道德經》安全
上面這段話出自老子的道德經的開篇,簡單說下前兩段話的意思:道彷佛有具體的定義,但總不是咱們所想象出的定義,名取出了一個名,但不必定咱們會一直使用。下面幾段就是對有(名)和無(道)的辯證關係,最後得出:「無」是天地的來處,「有」是衍生萬物的結果,這二者之間,同出爲意義不同,一樣好似玄妙務必,無窮無盡,切是研究一切的門經。數據結構
爲何會引用道德經?其實在我看來,老子不作軟件開發真是太虧了(哈哈),什麼是實體和對象?可能每一個人都有本身的解讀,就像上面討論的實體和值對象,其實某種意義上來講應該是領域對象和對象屬性,這裏說對象屬性也並非準確,就好比項目中咱們使用的屬性字典,並非任何一種對象的屬性,只是一個特定的值,不依附於任何對象。實體雖然稱做實體,實際上是一個對象,值對象雖然稱做對象,但其實只是一個特定值,意義就像」道可道,很是道,名可名,很是名「同樣,app
老子探討的有無關係,其實在軟件編程中就是實體和對象的關係,「有」能夠看作是「實體」,「無」能夠看作是「對象」,無衍生出有,有體現出無,就像實體和對象之間的關係,實體是否是對象?對象是否是實體?實體和對象到底什麼?這其實只是存在一個邊界問題。正如DDD中,實體便是領域對象,對象便是實體模型,咱們生活中經常討論:「是先有的雞蛋?仍是先有的雞?」最後都沒有得出一個準確的結果,若是老子來回答這個問題,就六個字:「雞生蛋,蛋生雞」,至於解釋,老子揮一揮衣袖,騎上青牛遠去-「本身去琢磨吧」。分佈式
故常無慾以觀其妙,常有欲以觀其徼(jiào)。 --《道德經》工具
這段話我以爲是道德經開篇的精髓,你可能從字面上能夠體會獲得一些內容,這其實一種態度,一種生活態度,一種編程態度。
「故常無慾以觀其妙」,這句話在咱們的現實生活中能夠很好的去解讀,世間萬物是如此的大,咱們還有不少的事物沒有去認知,因此咱們就會抱着征服的慾望去探尋,看到美好的事物就想去掠奪佔有,就像當你偶然發現一朵很是漂亮的鮮花,不少人不會停留下去欣賞它,而是去採摘它,而後據爲己有,生活中的例子比比皆是,就像文章會犯錯同樣。
老子的所提倡的就是咱們應該保持「無慾」的心態去看待事件萬物,去觀察,去體會它的玄妙,上面所說的掠奪、佔有,就不是「觀」所蘊含的意義了。咱們在作項目中,項目前期需求尚未肯定好就去開發,到最後弄得進退兩難,在DDD中,業務需求是很重要的一環,咱們應該花更多的時間去了解它、體會它、肯定它,而不是想固然的瞭解後就去開發項目,這也是建模專家所必備的基本條件。
「常有欲以觀其徼」,這句話的中的精髓就一個字「徼」,徼翻譯爲邊界的意思,「有欲」在現實生活中能夠指一些有名望、有地位、有財富的人,這些人當擁有了一些常人所不能擁有的東西后,並不懂得收斂和知足,反而使本身的慾望心更大,想獲得更大的知足,獲得後還想獲得,沒有一個界限,最後的下場通常都是很慘,就像和珅貪得無厭同樣。
老子所提倡的就是咱們在「有欲」以後,要觀察、體會一個界限,要使本身的「欲」控制在這個界限中,水滿則溢就是這個道理。就像在DDD中,實體和值對象邊界的肯定同樣。
含德之厚,比於赤子。
專氣致柔,能如嬰兒乎?
爲天下豁,常德不離,復歸於嬰兒。
--《道德經》
老子在道德經中屢次提到有關嬰兒的話題,就像上面幾句,老是拿一些事物和嬰兒進行比較,難道說老子喜歡嬰兒?準確的應該說,老子推崇嬰兒的那種狀態,何種狀態?無慾無求、迴歸天然、保持天性。。。
人的進化史進行了千百萬年,從最初的簡單生存原則,發展到如今複雜的人世關係,越進化越複雜,致使咱們如今越活越累。新出生的嬰兒沒有任何外界的摻雜,是如此的純淨,正如一碗清水通常,但隨着成長,慢慢的接觸外界事物,清水也會被染成五光十色,而失去了原本固有的一些東西,這也就是爲何老子推崇嬰兒的緣由。有時候咱們離開喧囂的城市,置身於寧靜的山坳,你會發現身心是如此的舒暢,其實這纔是咱們所固有的東西,只是處在亂世中,把那一抹清明掩蓋罷了。
什麼是初始實體和演化實體?這只不過是我本身定義的,這裏面的實體也能夠看作是對象,只是在DDD中稱做爲實體,如上面所說,嬰兒就像初始實體同樣,長大後的咱們就是演化實體,初始實體只有一種狀態,也就是一種原始狀態或者稱做是無狀態,特定的場景下初始實體只有一個抽象出來的對象,可是演化實體有不少種,但都是從初始實體演化出來的,因此稱爲演化實體,有直接的關係也有間接的關係,若是把嬰兒看作是初始實體,長大後的咱們是演化實體,但演化實體並不僅有長大後咱們,汽車、成績單、衣服等等一些與咱們相關的事物均可以稱爲演化實體,但長大後的咱們只是和初始實體有直接關係,其餘的和初始實體都是間接關係,這個特定的場景就是人類進化史。
固然有人看到這可能有些想法,認爲你這說的什麼亂七八糟的東西,沒有一點實際的意義。個人意思並非說明初始實體和演化實體是個什麼東西,而是說在咱們作項目的過程當中要找到那個「初始實體」,好比物流業務系統場景,在這個系統中哪一個是初始實體?調度?帳單?掃描?都不是,準確的說應該是運單,由於全部的業務操做都是圍繞它來展開,或者是由它演生而來,雖然初始實體咱們找到了,可是要仔細的揣摩它,肯定是出生的嬰兒仍是長大後的咱們?
聚合(Aggregate)和聚合根(Aggregate Root)是DDD中的重要概念,什麼是聚合?它經過定義對象之間清晰的所屬關係和邊界來實現領域模型的內聚,並避免了錯綜複雜的難以維護的對象關係網的造成,聚合定義了一組具備內聚關係的相關對象的集合,咱們把聚合看做是一個修改數據的單元。若是把人類社會看作是領域模型,聚合看作是一個國家,國家中的人是一個實體,那這個國家的人就是一個聚合根,可是每一個國家的人都是人,只不過膚色、語言、習俗會有些不一樣,能夠把人看作這個場景中的初始實體,也就是初始聚合根,而不是國家的人。
DTO(Data Transfer Object)數據傳輸對象,注意關鍵字「數據」兩個字,並非對象傳輸對象(Object Transfer Object),因此只是傳輸數據,並不包含領域業務處理,雖然用途只是傳輸數據,但自己其實也是對象,完成與領域對象之間的轉換,就像上面說的值對象同樣,某種意義上DTO能夠看作是值對象的集合,只不過是和領域對象之間的映射,不包含任何的業務邏輯。
爲何要使用DTO?主要緣由是隔離Domain Model,使改動領域模型而不影響UI,還有就是保持領域模型的安全,不暴露業務邏輯。還有就是在分佈式模式下,不一樣的場景使用相同的數據結構有不一樣的需求,而咱們又不得不作一些數據轉化,這是很繁瑣的,若是咱們在項目初期,作DTO的分析,這樣咱們就會省不少的事,並且還不會影響整個項目的業務流程,也方便之後對項目進行擴展。
下面咱們虛擬一個簡單「文章」領域模型:
1 public class Article : IEntity 2 { 3 public Article() 4 { 5 this.Id = Guid.NewGuid(); 6 } 7 public string Title { get; set; } 8 public string Content { get; set; } 9 public string Author { get; set; } 10 public DateTime PostTime { get; set; } 11 public string Remark { get; set; } 12 #region IEntity Members 13 /// <summary> 14 /// 讀取或設置文章的編號 15 /// </summary> 16 public Guid Id { get; set; } 17 #endregion 18 }
文章領域模型對應DTO:
1 public class ArticleDTO 2 { 3 /// <summary> 4 /// 文章惟一編碼 5 /// </summary> 6 public string ArticleID { get; set; } 7 /// <summary> 8 /// 文章標題 9 /// </summary> 10 public string Title { get; set; } 11 /// <summary> 12 /// 文章摘要 13 /// </summary> 14 public string Summary { get; set; } 15 /// <summary> 16 /// 文章內容 17 /// </summary> 18 public string Content { get; set; } 19 /// <summary> 20 /// 文章做者 21 /// </summary> 22 public string Author { get; set; } 23 /// <summary> 24 /// 文章發表日期 25 /// </summary> 26 public DateTime PostTime { get; set; } 27 /// <summary> 28 /// 文章發表年份 29 /// </summary> 30 public int PostYear { get; set; } 31 /// <summary> 32 /// 文章備註 33 /// </summary> 34 public string Remark { get; set; } 35 }
從上面ArticleDTO中能夠看到多了兩個屬性:Summary(文章摘要)和PostYear(文章發表年份),這就是咱們在特定的業務場景中須要的,並不會影響到領域模型,如何實現領域模型和DTO之間的轉換?咱們可使用AutoMapper能夠很方便的對他們進行轉換,一個強大的Object-Object Mapping工具。
工具-庫程序包管理器-程序包管理控制平臺,輸入「Install-Package AutoMapper」命令,就能夠把AutoMapper添加到項目中,有關AutoMapper相關文檔能夠參考:https://github.com/AutoMapper/AutoMapper/wiki,這邊簡單演示下Article到ArticleDTO之間的轉換。
1 static void Main(string[] args) 2 { 3 Article article = new Article 4 { 5 Title = "漫談實體、對象、DTO及AutoMapper的使用", 6 Content = "實體(Entity)、對象(Object)、DTO(Data Transfer Object)數據傳輸對象,老生常談話題,簡單的概念,換個角度你會發現更多的東西。我的拙見,勿喜請噴。", 7 Author = "xishuai", 8 PostTime = DateTime.Now, 9 Remark = "文章備註" 10 }; 11 //配置AutoMapper 12 AutoMapper.Mapper.Initialize(cfg => 13 { 14 cfg.CreateMap<Article, ArticleDTO>()//建立映射 15 .ForMember(dest => dest.ArticleID, opt => opt.MapFrom(src => src.Id))//指定映射規則 16 .ForMember(dest => dest.Summary, opt => opt.MapFrom(src => src.Content.Substring(0, 10)))//指定映射規則 17 .ForMember(dest => dest.PostYear, opt => opt.MapFrom(src => src.PostTime.Year))//指定映射規則 18 .ForMember(dest => dest.Remark, opt => opt.Ignore());//指定映射規則 忽視沒有的屬性 19 }); 20 21 //調用映射 22 ArticleDTO form = AutoMapper.Mapper.Map<Article, ArticleDTO>(article); 23 }
轉換效果:
其實這篇文章本來只是想簡單寫下DTO及AutoMapper的用法,可是不知怎的寫着寫着就寫跑偏了,如今回過頭看也不知道本身寫了些什麼東西,正如張三丰教張無忌太極劍法,問他記得了多少,最後什麼都沒記得。
隨着DDD(領域驅動設計)的學習和對道德經的感悟,就會發覺:此二者同出而異名,同謂之玄,玄之又玄,衆妙之門。
若是你以爲本篇文章對你有所幫助,請點擊右下部「推薦」,^_^
參考資料: