本文地址:http://www.cnblogs.com/outtamyhead/archive/2013/05/03/3056146.html,转载需保留本地址。
说在前面:
1、由于是头次翻译整本书籍,所以错误难免,希望大家都提出来,翻译的不好还望大家少拍砖多鼓励。
2、该系列没有按照原文直译,而是加入了我的一些言语在里面(在没有改变原意的情况下),所以大家在看的时候希望有所对照。
3、该系列每周出一或二篇博客,因为我最近很忙,一直在加班,很累的说。
4、该系列不提供原版文字,希望看原版的可以自行下载Pdf。
5、该系列省去了前面的废话,单刀直入,讲主体内容。
本章完结,有些内容和MVC无关,就没有翻译。
集合与简化
图3-5给为我们的域模型提供了一个很好的起点,但是它没有对如何利用C#和SQL Server实现模型提供任何有用的指示。如果我们加载一个成员到模型中,那么我们是否也应该加载它的报价以及与报价相对应的商品吗?如果可以,我们是否需要加载与这些商品相对应的其他所有报价以及形成这些报价的成员?当我们删除一个对象,我们也应该删除与之相关的对象--如果是这样,是哪些呢?如果我们选择使用文档存储代替关系型数据库存储来实现持久化,那么哪些对象集合代表一个单一文档?我们不知道,而且我们的域模型也不会告诉我们该怎么做。
而DDD回答这些问题的方式是把域对象放进一个叫做aggregates(集合)的组里--图3-6展示了如何在我们的拍卖域模型中集合这些对象。
一个集合实体包含多个域模型对象--有一个根实体来标识整个实体集合,并且是验证和持久化操作的“老板”。集合被视为处理数据更改的单一单元,所以我们需要生成集合来来使域模型场景中的关系有意义,并生成与实际业务过程逻辑对应的操作--也就是说,我们需要通过把作为一个组进行修改的对象进行分组的方法来生成集合。
DDD的关键规则是一个集合实体之外的对象只能保持对根实体的持久引用,而不是针对集合里的其他任何对象(事实上,一个非根对象的标识只需要在它集合内部保持唯一就可以)。这条规则强化了把一个集合中的对象当作单一单元的概念。
在我们的示例中,成员和商品都两个根集合,然而报价只能通过商品的上下文来访问(只能在商品的范围内进行访问),商品是它们(商品和报价)的集合。报价也只能被允许保持对成员的引用(成员是根实体),但是成员不能直接引用报价(因为报价不是根实体)。
集合的一个好处是它简化了在域模型中对象之间的关系--通常,这能增加被模拟域的自然属性。本质上,生成集合包含了域模型对象之间的关系所以它们看起来更像现实世界中真实存在的关系。清单3-1举例说明了我们的域模型用C#表示的样子。
1 public class Member { 2 public string LoginName { get; set; } // The unique key 3 public int ReputationPoints { get; set; } 4 } 5 public class Item { 6 public int ItemID { get; private set; } // The unique key 7 public string Title { get; set; } 8 public string Description { get; set; } 9 public DateTime AuctionEndDate { get; set; } 10 public IList<Bid> Bids { get; set; } 11 } 12 public class Bid { 13 public Member Member { get; set; } 14 public DateTime DatePlaced { get; set; } 15 public decimal BidAmount { get; set; } 16 }
注意我们是如何很容易的实现报价与成员之间的单向关系。我们也可以模拟其他的一些约束--例如,报价是不可变的(在常见的拍卖惯例中报价一旦形成就不能再改变)。运用集合允许我们生成一个比较有用的并且正确的域模型,我们已经用C#轻松的描述出来了。
一般情况下,集合对域模型添加结构和准确性。集合使得域模型更容易的运用验证(根对象在验证集合中所有对象的状态上变得越来越重要)而且是持久化的明显单元。因为集合实质上是我们域模型中的基本单元,它们也是数据库事务管理和级联删除中合适单元。
另一方面,它们可以在有时出现想象时施加限制--因为它们经常是想象的。集合自然的出现在文档数据库中,但是它们在SQL SERVER、大多数ORM工具中并不是原生的概念,要很好的实现它们,你的团队需要训练和有效的沟通。
定义存储库
在某些时候,我们需要为我们的域模型添加持久性--这通常通过一个关系数据库,对象数据库或者文档数据库来实现。持久性不是我们域模型中的一部分--它是我们关系分离模式中的一个中立的或垂直关注的存在。这意味着我们不想把处理持久性的代码和定义域模型的代码混合在一起。
把域模型和持久性系统强制分离的一种通常做法是定义存储库--这些对象代表底层数据库(或者文件存储或无论你选择是哪一个)。与其直接通过数据库工作,还不如利用域模型调用存储库定义的方法,然后反过来调用数据库去存储和检索模型数据--这允许我们在实现持久化过程中把模型进行隔离。
习惯做法是为每个集合定义单独的数据模型,因为集合是持久化的自然单元。在我们的拍卖示例中,举一个例子,我们也许会创建两个存储库--一个成员的,一个商品的(注意我们不需要报价存储库,因为它们会被持久化为商品集合的一部分)。清单3-2展示了这些存储库是怎么定义的。
1 public class MembersRepository { 2 public void AddMember(Member member) { 3 /* Implement me */ 4 } 5 public Member FetchByLoginName(string loginName) { 6 /* Implement me */ return null; 7 } 8 public void SubmitChanges() { 9 /* Implement me */ 10 public class ItemsRepository { 11 public void AddItem(Item item) { 12 /* Implement me */ 13 } 14 public Item FetchByID(int itemID) { 15 /* Implement me */ return null; 16 } 17 public IList<Item> ListItems(int pageSize, int pageIndex) { 18 /* Implement me */ return null; 19 } 20 public void SubmitChanges() { 21 /* Implement me */ 22 } 23 }
注意存储库只关注加载和保存数据--它们不包含域逻辑。我们可以通过在每个存储和检索操作方法上添加语句使这个存储库类变得完整。在第7章,我们将开始建立一个更加复杂和更真实的MVC应用程序,在那一节中,我们将告诉你如何通过使用Entity Framework来实现你的存储库。