《Pro ASP.NET MVC 3 Framework》學習筆記之四【領域模型介紹】

主題:應用領域驅動開發(Applying Domain-Driven Development)

Domain Model是MVC程序的"心臟",其他的一切,包括Controllers和Views僅僅是用來跟Domain Model交互的一種方式,ASP.NET MVC并沒有限制使用在Domain Model上面的技術,我們可以自由的選擇跟.net framework交互的技術,并且這樣的選擇是非常多的。不僅如此,ASP.NET MVC為我們提供了基礎的架構和約定來幫助Domain Model里面的Classes跟Controllers和Views的聯系,也包括跟MVC自己的聯系。

它們有三個關鍵的功能,如下所示:

a.模型綁定(Model Binding):是自動使用HTML表單提交的數據來組織領域對象(Domain Objects)基礎的約定。

b.模型元數據(Model metadata):描述了Model Classes對.net的所要表達的意思。舉例而言,就是給屬性賦予一個人容易理解的表述或者是對屬性呈現時的一些提示。asp.net mvc能夠自動的識別并對Model Classes合理的呈現到Views里面。

c.驗證(Validation):能夠在模型綁定時被執行,并且能夠應用被定義為元素據的那些規則。

如果你對于模型綁定(Model Binding)的理解也跟我一樣還不是很清楚,也沒有必要著急,更不要放棄對MVC的學習,因為書的后面章節會有詳細的講解 ,呵呵。現在我們先將ASP.NET MVC的實現放到一邊,單純思考下領域建模(Domain Modelling),下面使用.net和sql server創建一個簡單的競拍程序的領域模型。

一,創建一個簡單的領域模型

下面是要創建的競拍程序的類圖


上面的模型包含了一個Members的集合,每一個Member會有一個Bids集合,每一個Bid對應一個Item,每一個Item可以有多個來自不同Members的Bids

實現我們自己的domain model并作為一個獨立的組件其中一個關鍵的地方是我們選擇的語言和術語,這個不是我們的編程語言,而是領域建模的通用的語言。這種語言是開發人員和領域的專業人員都知道的,這樣主要是為了這兩種人能流暢的交流,而這卻是至關重要的。當領域的專家們不了解建模的一些概念時,我們應該針對使用的術語達成一個共識,這個共識就是創建一種通用的語言并貫穿在整個領域建模過程中。這樣做有很多的好處。

1.首先,開發人員傾向于使用編程語言,比如類名,數據庫等等名詞來表達。而業務專家們是不懂這些的,他們也不需要懂。業務專家知曉一些技術方面的知識是一件非常危險的事情,因為他們會經常根據自己對技術的理解來不斷篩選他們的需求,這也就意味著需求會頻繁的更改,進而導致開發人員也不知道業務專家的真實需求到底是什么。創建通用語言的方法能夠幫助我們避免在一個應用程序里面過度的泛化需求,程序員傾向于建立每一個可能業務實際模型,而不是具體到某一個業務需求。

2.在通用語言和領域模型之間的這種連接不應該是非常膚淺的而是向DDD(Domain-Driven Design)專家所建議的那樣:對通用語言的任何變化都會導致Model的變化。假如我們讓建模跟業務領域不同步,我們就需要建立一種從Model到domain映射的中間語言,從長遠來看,這種做法會導致災難。為此,我們將創建一個會兩種語言的特殊人類,他們隨后就開始篩選需求,這卻是建立在他們對兩種語言都不完全理解的基礎之上,當然這樣的后果可以想象。

二,聚合與簡化

上面的圖,為我們提供了一個很好的建模起點
但是上面圖示的模型并沒有提供用C#和SQL Server實現Model的任何有用的幫助,會有不少的問題困擾我們:

1.如果我們load一個Member進入內存,也是不是應該load Member的Bids以及相關的Items進入內存呢?

2.如果我們這樣做了,我們是否需要將這個Item其他的bids也load進內存,并且也將做這些Bids的Members一同load進內存呢?

3.當我們刪除一個對象時,我是否應該刪除相關的對象呢?如果是,又有哪些呢?

4.如果我們選擇用文檔存儲代替關系型數據庫來持久化,那哪一個對象的集合應該呈現到同一個文檔呢?

所有以上的問題,我們不知道作何解答,并且我們的領域模型也沒有給我們任何答案。

回答這些問題的DDD方式是將Domain Objects分配到組里面,這種方式稱為聚合(aggregates)。

下圖很好的展示了怎樣聚合在我們這個競拍程序里面的領域模型,如下所示:


一個聚合的實體組將若干領域對象聯合(Together)到了一起,有一個根實體被用來標識整個聚合,它在驗證和持久化操作里面充當了"boss"的角色。在數據變化時,我把聚合當作一個單元來統籌處理,所以我們需要創建呈現在領域模型上下文里面有意義的關系的聚合,并且創建跟實現業務過程一致的邏輯操作。也就是說,我們需要通過分組對象來創建聚合,而這些對象是可以作為一個組被改變的。

一個非常重要的DDD規則是,在一個聚合實例范圍外的對象,只能通過對根實體(root entity)的引用來持久化,而不是引用在聚合里面的對象。這條規則強化了將聚合里面的對象作為一個單元來對待的概念。在本例子里面,Members和Items都是聚合的根,而Bids只能在作為它們聚合根實體的Item的上下文(the context of Item)里面被訪問。Bids可以引用Members(根實體),但是Members不能引用Bids(不是根實體)

聚合的一個好處是簡化了對象跟領域模型之間的關系,通常這樣能夠幫助我們對需要建模的領域的本質的理解。本質上講,創建聚合約束領域模型和對象之間的關系使得這種關系更加接近于現實領域里面存在的關系。下面是用C#來表達的,如下所示:

public class Member {
public string LoginName { get; set; } // The unique key
public int ReputationPoints { get; set; }
}
public class Item {
public int ItemID { get; private set; } // The unique key
public string Title { get; set; }
public string Description { get; set; }
public DateTime AuctionEndDate { get; set; }
public IList<Bid> Bids { get; set; }
}
public class Bid {
public Member Member { get; set; }
public DateTime DatePlaced { get; set; }
public decimal BidAmount { get; set; }
}

從上面的代碼可以看出,我們很容易就捕捉到了Bids和Members之間的單向關系的本質,當然我們也可以建立一些其他的約束。例如:Bids是不可變的,這也是符合實際的。應用聚合能夠幫助我們建立更加有用,更加精確的領域模型,也能夠讓我們用C#熟練的實現。

一般來講,聚合為一個領域模型增加了結構化和精確化。這也使得應用驗證變得容易(根實體負責驗證聚合里面所有對象的的狀態),這很明顯也是持久化的單元。由于聚合的本質就是領域模型的原子單元,它們也能夠適用事務管理的單元和級聯從數據庫刪除的單元。

另一方面,聚合常常是人為加上限制。聚合(Aggregates)的概念能夠很自然的從文檔型數據庫得到,但它不是sqlserver本身的概念,也不是存在大部分ORM工具里的概念,為了很好的實現它們,我們的團隊需要科學有效的溝通。

三,定義倉庫(Defining Repositories)

在某些時候,我們需要給領域模型添加持久化,這通常是通過關系型,對象型,或文檔型的數據庫來做。持久化不是我們領域模型的一部分,它是一個獨立的關注點,這也就意味著我們不能將持久化的代碼跟定義領域模型的代碼混合到一起。解決這個問題通常的方式就是定義一個倉庫(Repositories)

Respositories是基于數據庫(可能你選擇的是文件存儲等等)層面的對象呈現。領域模型通過調用定義在Repositories的方法來間接的存儲和查詢數據庫,這使得我們的Model可以獨立于持久化的實現。這樣約定就是為每一個聚合(Aggregates)定義單獨的數據模型。在我們的競拍程序里面,我們可以創建2個Repositories,它們分別是針對Members的Repository和針對Items的Repository。注意這里,我們并不需要創建針對Bids的Repository,因為Bids會作為Items聚會持久化的一部分)。

下面是定義的兩個Repositories,如下所示:

public class MembersRepository {
public void AddMember(Member member) { ... }
public Member FetchByLoginName(string loginName) { ... }
public void SubmitChanges() { ...}
}
public class ItemsRepository {
public void AddItem(Item item) { ...}
public Item FetchByID(int itemID) { ... }
public IList<Item> ListItems(int pageSize,int pageIndex) { ...}
public void SubmitChanges() { ... }
}

特別需要注意:Repositories僅僅針對Loading和Saving Data.它們不包含任何其他的邏輯。

今天的筆記做到這里,我也是剛學習MVC,做筆記是為了鞏固和加深理解,當然如果能給到那些跟我一樣的初學者一點點的幫助,我就非常高興了。筆記里面肯定會有我理解不對的地方,還請路過的大牛們多多幫助指導。謝謝!
祝路過的朋友工作順利!

晚安!

轉載于:https://www.cnblogs.com/mszhangxuefei/archive/2011/12/04/mvcnotes_4.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/380053.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/380053.shtml
英文地址,請注明出處:http://en.pswp.cn/news/380053.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java——集合框架(List)

集合框架&#xff08;List的三個子類的特點&#xff09; A&#xff1a;List的三個子類的特點 ArrayList&#xff1a; 底層數據結構是數組&#xff0c;查詢快&#xff0c;增刪慢。 線程不安全&#xff0c;效率高。 Vector&#xff1a; 底層數據結構是數組&#xff0c;查詢…

一步一步學pwntools(適合新手)

序 pwntools是一個二進制利用框架。官方文檔提供了詳細的api規范。然而目前并沒有一個很好的新手教程。因此我用了我過去的幾篇writeup。由于本文只是用來介紹pwntools使用方法&#xff0c;我不會過于詳細的講解各種二進制漏洞攻擊技術。 Pwntools的“Hello World” 棧溢出無…

關于J2EE中死鎖問題的研究(1)

大多數重要的應用程序都涉及高度并發性和多個抽象層。并發性與資源爭用有關&#xff0c;并且是導致死鎖問題增多的因素之一。多個抽象層使隔離并修復死鎖環境的工作變得更加困難。 通常&#xff0c;當同時執行兩個或兩個以上的線程時&#xff0c;如果每個線程都占有一個資源并請…

python變量分配內存_Python | 聲明任何變量而不分配任何值

python變量分配內存Since, Python is a dynamic programming language so there is no need to declare such type of variable, it automatically declares when first time value assign in it. 由于Python是一種動態編程語言&#xff0c;因此無需聲明此類變量&#xff0c;它…

UVA 10004 - Bicoloring

模擬染色&#xff0c;因為只有兩種顏色&#xff0c;所以分別用 0、 1 代表這兩種顏色&#xff0c;然后從0開始深搜&#xff0c;如果 每個點都能染上色&#xff0c;且相鄰兩點的顏色不同&#xff0c;則符合要求。 #include<stdio.h>#include<string.h>#define MAXN …

標志寄存器:CF、PF、AF、ZF、SF、TF、DF、OF

注&#xff1a;下面說到的標志寄存器都是縮寫&#xff0c;C就是CF&#xff0c;其他也一樣 標志寄存器&#xff1a;C、P、A、Z、S、T、D、O的內容只會是0或1&#xff0c;0表示假&#xff0c;1表示真 O&#xff1a;溢出標志 一個寄存器如果存放的值超過所能表示的范圍&#xf…

揭秘:銷售人員26個致命弱點

銷售人員有許多積極的態度需要學習&#xff0c; 同時也有許多不良的習慣應該避免&#xff0c;以免影響個性及專業能力。仔細看看這些缺點&#xff0c;反省你自己&#xff0c;還需要改善的畫&#xff0c;直到你給自己一百分為止。找一位深知你的好 友&#xff0c;讓他誠實地給你…

Java——集合(練習題)

例題1&#xff1a;產生10個1~20之間的隨機數&#xff0c;要求隨機數不能重復 import java.util.HashSet; import java.util.Random; public class Test1 {/*** 產生10個1~20之間的隨機數&#xff0c;要求隨機數不能重復* * 分析&#xff1a;* 1,有Random類創建隨機數對象* 2&a…

模塊化 組件化 工程化_軟件工程中的模塊和軟件組件

模塊化 組件化 工程化The module in software is a small part of the software that is responsible for performing any kind of functionality. Sometimes, the term sub-program is also used to refer to the term module. 軟件中的模塊是軟件的一小部分&#xff0c;負責…

Firefox2狂占CPU解決辦法

https://images.cnblogs.com/cnblogs_com/Tisty/138006/o_firefox3.jpg 看了一下&#xff0c;不知道 "jpeg_free_large" 是干啥的&#xff0c;遂用 "Firefox jpeg_free_large" Google 一下&#xff0c;出來的一堆東西里有帖子說可能和 Apple 的 QuickTime …

PUSHAD和POPAD,以及PUSHA和POPA

PUSHAD PUSHAD也叫保護現場&#xff0c;就是把我們的寄存器壓入棧中 pushad是把eax&#xff0c;ecx&#xff0c;edx&#xff0c;ebx&#xff0c;esp、ebp&#xff0c;esi&#xff0c;edi依次壓入棧中&#xff0c;ESP會減少32&#xff0c;相當于&#xff1a; push eax push ec…

Java——n個數的全排列

例題&#xff1a; 輸入一串字符串&#xff0c;將該字符串中的字符元素進行全排列&#xff0c;然后&#xff0c;一串輸出結果。 例如&#xff1a; 輸入&#xff1a; ABCD 輸出&#xff1a; ABCD ABDC ACBD ACDB ADBC ADCB BACD BADC BCAD BCDA BDAC BDCA CABD CADB CBAD CBDA…

一段個性化stringgrid的代碼

需要注意的是 該段程序使用了 canvas。 procedure TW_CkbTaiZhang.KhLstDrawCell(Sender: TObject; ACol,ARow: Integer; Rect: TRect; State: TGridDrawState);begin if ARowkhlst.Row then with khlst.Canvas do //畫 cell 的邊框 begin Pen.Color : $00ff0000; …

dp 扔雞蛋_使用動態編程(DP)的雞蛋掉落問題

dp 扔雞蛋Problem statement: You are given N floor and K eggs. You have to minimize the number of times you have to drop the eggs to find the critical floor where critical floor means the floor beyond which eggs start to break. Assumptions of the problem: 問…

MOVSX和MOVZX

MOVSX 先符號擴展,再傳送 格式&#xff1a; MOVSX 操作數A &#xff0c;操作數B //操作數B的空間小于A比如說我們使用命令&#xff1a; movsx eax&#xff0c;bxbx是16位&#xff0c;eax是32位&#xff0c;傳值過程&#xff1a; 先用bx的符號位把eax高16填滿&#xff0c;b…

統計學習以及支持向量機的國內外基本比較重要的書

1、支持向量機導論&#xff0c;此書乃是SVM方面的經典著作&#xff0c; 該書的作者也是近年來SVM、kernel methods學術圈內的活躍學者&#xff0c;對于這些領域均有過重要的貢獻。這本書從“線性機器、核方法、統計學習理論、凸優化”四個方面揭示了SVM的內在機理 --利用核…

Java——集合(TreeSet)

package com.wsq.set; //這里進行調用Person()方法&#xff0c;要進行導包 import java.util.TreeSet; import com.wsq.bean.Person; public class Demo3_TreeSet { /*** TreeSet集合是用來對元素進行排序的&#xff0c;同樣它也可以保證元素的唯一* 當compareTo()方法返…

setmonth_日期setMonth()方法以及JavaScript中的示例

setmonthJavaScript日期setMonth()方法 (JavaScript Date setMonth() method) setMonth() method is a Date class method, it is used to set the month to the Date object with a valid month value (between 0 to 11. 0 for January, 1 for February and so on). setMonth(…

LEA與XCHG

LEA 格式&#xff1a; LEA 通用寄存器 內存地址功能&#xff1a;取地址命令 將內存地址賦值給寄存器 lea eax,dword ptr ds:[ecx0x16]dword 雙字 就是四個字節ptr pointer縮寫 即指針ds 數據段版寄存器[]里的數據是一個地址值&#xff0c;這個地址指向一個雙字型數據 將dwo…

分域名優化的時候要考慮備選IP的問題

我們在需要下載很多內容的時候&#xff0c;很容易想到做分域名的并發下載&#xff0c;給原來的服務器多分幾個域名&#xff0c;因為分不同的域名可能可以在瀏覽器中分到更多的下載進程&#xff0c;提高下載速度。 但是在做網絡應用的時候&#xff0c;我們的一個域名下面有的時候…