一样详尽阳光:DDD(领域让设计)应针对具体事情场景,如何聚焦 Domain Model(领域模型)?

By admin in 亚洲必赢app在哪下载 on 2018年11月13日

描绘在前面

亚洲必赢app在哪下载 1

  阅读目录:

  • 问题来自是呀?
  • 《领域让设计-软件基本复杂性应针对的志》分层概念
  • Repository(仓储)职责所在?
  • Domain
    Model(领域模型)重新设计
  • Domain
    Service(领域服务)的入
  • MessageManager.Domain.Tests
    的加入
  • Application
    Layer(应用层)的协调?
  • Unit Of
    Work(工作单元)工作范围与贯彻?
  • 本子发布
  • 后记

  于达到一样篇《自我的“第一糟糕”,就这么没有了:DDD(领域让设计)理论结合履行》博文被,简单介绍了世界让设计之一些理念,并简短好因领域让设计之具体品种 MessageManager,本人在计划
MessageManager 项目事先,并没扣了 Eric
Evans 的《Domain-Driven Design
–Tackling Complexity in the Heart of Software》和 Martin Fowler
的《Patterns of Enterprise Application
Architecture》,《企业应用架构模式》这本书在读书,关于世界让设计,主要学习来是花园被的
netfocus、dax.net、以及清培兄的部分博文(小弟先以此谢过各位大神的无私奉献),还有即使是解道中之圈子让设计专题,当然还有一对来源搜索引擎的片材料,再添加自己之片段琢磨和喻,也即变成了属自己之“领域让设计”。

  MessageManager
项目是针对团结所理解领域让设计的查检,如果你细心看罢上等同篇博文,你晤面发现 MessageManager
其实只是世界让设计之“外壳”,就像咱种植黄瓜,首先要长一个作风,以便黄瓜的生,MessageManager
项目即使相当给这个架子,核心之事物“黄瓜”并无在,当时在规划完 MessageManager
项目的时刻,其实都意识问题之留存,所以在博文最后留给了脚两个问题:

  • Domain
    Model(领域模型):领域模型到底该怎么统筹?你晤面相,MessageManager
    项目中的 User 和 Message
    领域模型是充分贫血的,没有包含其他的事情逻辑,现在网上广大有关 DDD
    示例项目多数也存在这种状况,当然项目本身并未事情,只是简短的“CURD”操作,但是倘若是片大型项目的错综复杂工作逻辑,该怎么去贯彻?或者说,领域模型就什么样的事情逻辑?什么才是真的事体逻辑?这个题目特别重点,后续探讨。
  • Application(应用层):应用层作为协调服务层,当遇到复杂的事务逻辑时,到底怎样落实,而未苟该变成
    BLL(业务逻辑层)?认清本质很重要,后续探讨。

  另外又糊有园友们于达成同一首之问题评论:

亚洲必赢app在哪下载 2

亚洲必赢app在哪下载 3

亚洲必赢app在哪下载 4

  关于以上之题目,本篇博文只是做一些解读,希望可以针对那些迷恋于世界让设计的恋人等有的启示,写得起不当之处,也接指出。

题材来自是什么?

亚洲必赢app在哪下载 5

  出现上述问题的由是呀?需求略?设计无成立?准确之吧,应该还不是,我觉着问题之来源是没有当真去领略领域让设计,或者说没有真正用世界让设计的见去规划要实现,领域让设计之概念网上同找一格外堆,你看罢几篇稿子以后呢能够写出来之类的章,为什么?因为都是泛泛之谈,诸如:领域模型是世界让之基本;领域让基本分为四层(用户层、应用层、领域层与基础层);领域涵盖实体、值对象以及劳动;还有部分聚众和聚合根之类的概念等等,文中也会见吃你列有有有关这些概念的代码实现,让你瞬间感觉到原来领域让设计是这般的壮烈上。

  但倘若拿这些概念去实践吧?却从不是那么回事,现在以领域让设计去支付之店堂实际是极度少了,原因产生过多种,下面大致列出有些:

  • 开发成本太强,换句话说,就是一旦下领域让设计开,需要请高级程序员、高级架构师和建模专家,一般这种开发人员薪资还比较高,老板确实舍得啊?
  • 开发周期长,花在要求分析的时日较丰富,甚至比程序实现还要长,这个对业主来说是格外的,开发周期长,一般会意味着企业之创收降低,公司赢利下滑,老板的钱管就是瘪了,老板会甘愿为?
  • 付出考虑转变问题,使用世界让设计开发,需要企业里的程序员懂得领域让设计,要指向面向对象(OO)设计出早晚的了解,现实情况是,大部分的程序员虽然采取的是面向对象语言(比如
    Java、C#),却做在面向过程的从事(类似 C
    语言函数式的开销)。现在受商家的程序员使用领域让设计开,就哼于原先是为此手直接用,现在叫您采取筷子用,你会习惯吗?这得同种植变更,很多程序员会很无惯,这也是天地让设计执行难之关键因。
  • 关于世界让设计实践经验实在太少,大家脑子被只有模模糊糊的定义,却无翔实的推行,像
    dax.net
    这样去得几单总体基于领域让设计类之百般神实在尽少了,很多都是比如说我同,理解有定义后,放出一个简练的以身作则
    Demo,然后就是没有然后了。

  Eric Evans 以2004年提出 DDD(领域让设计)的见解,距今已十年了,推广也停滞不前,确实值得咱们程序员去反思。

  扯得生硌多了,回到这可标题:题材的来源于是啊?答案恐怕会不叫你称心,就是从未当真懂领域让设计。那么你或会咨询:那的确的天地让设计是呀?这个我眷恋就发生
Eric Evans
可以应对,但为无须把世界让设计看得这么绝对,领域让设计仅是如出一辙种植点,具体的落实而就此现实的主意,正而发生句古话:师父受上家,修行在个人。每个人发每个人之切实可行悟道,但再变也不用忘记了师出同门。

  还有一些即是,有朋友指出简单的政工逻辑是反映不起天地让设计的,关于这或多或少先是我是于赞成的,但如果失去用一些巨型业务场景去开领域让设计的言传身教,我个人觉得也未极端现实,毕竟时间本不过胜了。我个人觉得小之工作场景和怪的作业场景都得以用世界让设计实现,只是工作逻辑的复杂度不同,还有就是是适用度也不比,小之业务场景用脚本驱动模式去贯彻,可能会见于世界让设计区实现重复简便易行、快速,但是只是凡是业务场景(不论大小),必然蕴含业务逻辑(CRUD
除外),那也尽管足以采用世界让设计去付出,还是那么句话,只是不绝相符,但做示范示例还是得的。

  业务逻辑的复杂度主要反映于天地模型中,复杂性的事务逻辑,领域模型也即越是繁杂,但和简单性的领域模型实质是均等的。关于什么真正懂得领域让设计?这同一接触我个人觉得方法就是是“迭代”,惟有时时刻刻的失去执行,不断的失体会,才能够真的的去领略领域让设计,就比如
MessageManager
项目,每一样软稍体会我就是会见认为这么做不成立,那么就是推倒重建,可能这么做而未客观,那便推倒重重建。。。

  闲话少说,来拘禁即无异不好的“迭代”:

《领域让设计-软件基本复杂性应针对的道》分层概念

  流动:这同样节点是我后面长的,真是造化,在自我写这篇博客的上,正好有各类不出名的爱侣,发信息说他看到自己事先的相同首博文,我以和平被跪求《领域让设计-软件基本复杂性应针对的道》这按照开,因为网上没得购买。正好他出
Word
版,虽然情稍错别字,但是诚感谢这员不知名的心上人。大致阅读了生目录结构,确实是自个儿眷恋使之,接下会认真的拜读,有实质书的语当然还好,下面是拣自即按照开的子概念。

亚洲必赢app在哪下载 6

  于面向对象的主次中,用户界面(UI)、数据库及其他支持代码,经常吃一直写到业务对象被失。在UI和数据库脚本的行事中嵌入额外的事务逻辑。出现这种景象是因从短期的见看,它是如系统运转起来的顶爱的不二法门。当跟天地有关的代码和大气底其他代码乱在共同时,就那个麻烦阅读并理解了。对UI的简短改动就见面改工作逻辑。改变工作规则可能需要小心翼翼地跟踪UI代码、数据库代码或者其它的次序元素。实现同的型驱动对象变得无切实际,而且自动化测试为难以使用。如果以先后的每个行为遭到包括了颇具的艺和逻辑,那么其必须十分粗略,否则会难以知晓。

  将一个犬牙交错的顺序开展层次划分。为各一样叠开展设计,每层都是内聚的以只是依靠让其的下层。采用专业的架构模式来完成及上层的松弛关联。将有着与世界模型相关的代码都集中在同一重合,并且将它们和用户界面层、应用层和基础结构层的代码分离。领域对象可以以第一在表达领域模型上,不需关爱其自己之显示、存储和管制使用任务等情节。这样要模型发展得足够长以及清,足以吸引本质之业务知识并贯彻其。

用户界面层(表示层) 负责向用户显示信息,并且解析用户命令。外部的执行者有时可能会是其他的计算机系统,不一定非是人。
应用层 定义软件可以完成的工作,并且指挥具有丰富含义的领域对象来解决问题。这个层所负责的任务对业务影响深远,对跟其他系统的应用层进行交互非常必要这个层要保持简练。它不包括处理业务规则或知识,只是给下一层中相互协作的领域对象协调任务、委托工作。在这个层次中不反映业务情况的状态,但反映用户或程序的任务进度的状态
领域层(模型层) 负责表示业务概念、业务状况的信息以及业务规则。尽管保存这些内容的技术细节由基础结构层来完成,反映业务状况的状态在该层中被控制和使用。这一层是业务软件的核心。
基础结构层 为上层提供通用的技术能力:应用的消息发送、领域持久化,为用户界面绘制窗口等。通过架构框架,基础结构层还可以支持这四层之间的交互模式。

  一个靶所表示的东西是一个兼有连续性和标识的定义(可以跟踪该事物经历之两样之状态,甚至足以让该事物跨越不同的贯彻),还是仅仅是一个就此来描述事物的某种状态的属性?这就是实业和价值对象极其核心的别。明确地选用这有限栽模式中的同等种植来定义对象,可以要对象的义还清楚,并可引导我们组织出一个健壮的设计。

  另外,领域面临尚设有不少底端,如果因此行止或者操作来讲述其会比用对象来讲述更加分明。尽管与面向对象建模理念稍有矛盾,但这些极端是因此劳动来讲述,而不是用以此操作的任务强加到一点实体或值对象身上。服务用来呢客户要提供劳务。在软件的技术层中就是出许多劳动。服务吗会见当圈子中冒出,它们用于对软件要就的有些动开展建模,但是和状态无关。有时我们不能不于靶模型中釆取一些投降的方法——这是不可避免的,例如使用关系数据库进行仓储时便会见现出这种情形。本章将会见叫来部分规则,当遇这种复杂气象常,遵守这些规则可使我们保障是的势头。

  最后,我们针对模块(Module)的讨论好协助了解这样的见地:每个规划决策都应是基于对世界的正确理解来做出。高内聚、低关联这种想往往给视作是上佳的技术标准,它们对于概念本身为是适用的。在范驱动的统筹受到,模块是范的一模一样有些,它们该能体现来天地中的定义。

Repository(仓储)职责所在?

  言归正题。

  Repository(仓储)的概念好参照:http://www.cnblogs.com/dudu/archive/2011/05/25/repository_pattern.html,我个人于支持
dudu 的敞亮:Repository
是一个单身的重叠,介于领域层与数映射层(数据访问层)之间。它的有让世界层备感不至数访问层的是,它提供一个看似集合的接口提供给世界层开展领域对象的访问。Repository
是仓管理员,领域层需要什么事物只待报仓库管理员,由仓库管理员将东西拿给她,并不需要知道东西实际在哪。

  关于 Repository
的概念,在《企业应用架构模式》书被吗产生说明:和谐领域与多少映射层,利用类似于聚集的接口来聘领域对象。开中把
Repository 翻译啊资源库,其实是暨储存是一个意,关于 Repository 这无异于节点的情,我大致阅读了两三篇才理解了有情(这本开比较空虚难理解,需要差不多读几遍,然后根据自己的明进行推敲酝酿),文中也为有了一个示范:查找一个人口所当的机构(Java),以便让强化对
Repository 的接头。

  我们先行押一下 Repository
的定义前半句:协调领域与数目映射层,也不怕是 dudu
所说的在于领域层以及多少映射层之间,理解这同触及老关键,非常主要。然后我们再度来拘禁
MessageManager 项目中关于 Repository
的用(实现无问题),在哪用为?根据定义我们应该要错过世界层去找寻 Repository 的下,但是我们当
MessageManager.Domain 项目受到找不顶有关 Repository
的半毛应用,却以 MessageManager.Application
项目中找到了:

  1 /**
  2 * author:xishuai
  3 * address:https://www.github.com/yuezhongxin/MessageManager
  4 **/
  5 
  6 using System;
  7 using System.Collections.Generic;
  8 using AutoMapper;
  9 using MessageManager.Application.DTO;
 10 using MessageManager.Domain;
 11 using MessageManager.Domain.DomainModel;
 12 using MessageManager.Domain.Repositories;
 13 
 14 namespace MessageManager.Application.Implementation
 15 {
 16     /// <summary>
 17     /// Message管理应用层接口实现
 18     /// </summary>
 19     public class MessageServiceImpl : ApplicationService, IMessageService
 20     {
 21         #region Private Fields
 22         private readonly IMessageRepository messageRepository;
 23         private readonly IUserRepository userRepository;
 24         #endregion
 25 
 26         #region Ctor
 27         /// <summary>
 28         /// 初始化一个<c>MessageServiceImpl</c>类型的实例。
 29         /// </summary>
 30         /// <param name="context">用来初始化<c>MessageServiceImpl</c>类型的仓储上下文实例。</param>
 31         /// <param name="messageRepository">“消息”仓储实例。</param>
 32         /// <param name="userRepository">“用户”仓储实例。</param>
 33         public MessageServiceImpl(IRepositoryContext context,
 34             IMessageRepository messageRepository,
 35             IUserRepository userRepository)
 36             :base(context)
 37         {
 38             this.messageRepository = messageRepository;
 39             this.userRepository = userRepository;
 40         }
 41         #endregion
 42 
 43         #region IMessageService Members
 44         /// <summary>
 45         /// 通过发送方获取消息列表
 46         /// </summary>
 47         /// <param name="userDTO">发送方</param>
 48         /// <returns>消息列表</returns>
 49         public IEnumerable<MessageDTO> GetMessagesBySendUser(UserDTO sendUserDTO)
 50         {
 51             //User user = userRepository.GetUserByName(sendUserDTO.Name);
 52             var messages = messageRepository.GetMessagesBySendUser(Mapper.Map<UserDTO, User>(sendUserDTO));
 53             if (messages == null)
 54                 return null;
 55             var ret = new List<MessageDTO>();
 56             foreach (var message in messages)
 57             {
 58                 ret.Add(Mapper.Map<Message, MessageDTO>(message));
 59             }
 60             return ret;
 61         }
 62         /// <summary>
 63         /// 通过接受方获取消息列表
 64         /// </summary>
 65         /// <param name="userDTO">接受方</param>
 66         /// <returns>消息列表</returns>
 67         public IEnumerable<MessageDTO> GetMessagesByReceiveUser(UserDTO receiveUserDTO)
 68         {
 69             //User user = userRepository.GetUserByName(receiveUserDTO.Name);
 70             var messages = messageRepository.GetMessagesByReceiveUser(Mapper.Map<UserDTO, User>(receiveUserDTO));
 71             if (messages == null)
 72                 return null;
 73             var ret = new List<MessageDTO>();
 74             foreach (var message in messages)
 75             {
 76                 ret.Add(Mapper.Map<Message, MessageDTO>(message));
 77             }
 78             return ret;
 79         }
 80         /// <summary>
 81         /// 删除消息
 82         /// </summary>
 83         /// <param name="messageDTO"></param>
 84         /// <returns></returns>
 85         public bool DeleteMessage(MessageDTO messageDTO)
 86         {
 87             messageRepository.Remove(Mapper.Map<MessageDTO, Message>(messageDTO));
 88             return messageRepository.Context.Commit();
 89         }
 90         /// <summary>
 91         /// 发送消息
 92         /// </summary>
 93         /// <param name="messageDTO"></param>
 94         /// <returns></returns>
 95         public bool SendMessage(MessageDTO messageDTO)
 96         {
 97             Message message = Mapper.Map<MessageDTO, Message>(messageDTO);
 98             message.FromUserID = userRepository.GetUserByName(messageDTO.FromUserName).ID;
 99             message.ToUserID = userRepository.GetUserByName(messageDTO.ToUserName).ID;
100             messageRepository.Add(message);
101             return messageRepository.Context.Commit();
102         }
103         /// <summary>
104         /// 查看消息
105         /// </summary>
106         /// <param name="ID"></param>
107         /// <returns></returns>
108         public MessageDTO ShowMessage(string ID, string isRead)
109         {
110             Message message = messageRepository.GetByKey(ID);
111             if (isRead == "1")
112             {
113                 message.IsRead = true;
114                 messageRepository.Update(message);
115                 messageRepository.Context.Commit();
116             }
117             return Mapper.Map<Message, MessageDTO>(message);
118         }
119         #endregion
120     }
121 }

对,你早已发现了 Repository
的踪迹,Repository
应用在应用层,这样就是造成应用层和基础层(我把多少持久化放在基础层了)通信,忽略了极要害的领域层,领域层在里起及之意最多吧就是传递一个可怜贫血的圈子模型,然后经过
Repository
进行“CRUD”,这样的结果是,应用层不化所谓的
BLL(常说的业务逻辑层)才怪,另外,因为作业逻辑都居应用层了,领域模型呢换得更其贫血。

  以上分析可以答应上等同篇中遗留的题材:应用层作为协调服务层,当遇复杂的政工逻辑时,到底哪实现,而不若其成为
BLL(业务逻辑层)?其实关于率先独问题(领域模型如何规划无贫血)也是好拓展解答的,这个后同节省点出证实,关于这无异于多级题材的诱致自己觉着即使是
Repository
设计,出现了重以及驳斥偏移,以致于无将设计重点作于作业逻辑上,在这个与大家说声抱歉。

  关于“应用层中的事体逻辑”,比如下面这段代码:

 1         /// <summary>
 2         /// 查看消息
 3         /// </summary>
 4         /// <param name="ID"></param>
 5         /// <returns></returns>
 6         public MessageDTO ShowMessage(string ID, string isRead)
 7         {
 8             Message message = messageRepository.GetByKey(ID);
 9             if (isRead == "1")
10             {
11                 message.IsRead = true;
12                 messageRepository.Update(message);
13                 messageRepository.Context.Commit();
14             }
15             return Mapper.Map<Message, MessageDTO>(message);
16         }

  对,你就扣押出来了,查看消息,要因阅读人,然后判断是否已读,如果是读人是收件人,并且信息是匪念状态,要管此消息置为早已读状态,业务逻辑没什么问题,但是却加大错了职(应用层),应该放在领域层中(领域模型),其实这都是
Repository
惹的迫害,因为应用层根本没和天地层通信,关于世界模型的筹划下节点有讲解。

  看了上述之情节,是免是多少:拨开浓雾,见晴天的感觉到?不明白乃来没产生?反正自己是出,关于
Repository
我们再度明白的那个一点,先看一下继半句之概念:下类似于聚集的接口来聘领域对象。恰巧而
dudu 理解的这么:Repository
是仓管理员,领域层需要什么事物只待报仓库管理员,由仓库管理员将东西拿给她,并不需要知道东西实际在哪。可以这样理解也 Repository
就如一个询问集合,只供查询给世界层,但是我们发现在实质上应用中 Repository
也提供了持久化操作,这一点的确给 Repository
有点莫名其妙了,关于这同碰自己看 CQRS(Command Query Responsibility
Segregation)模式可挺好之化解,翻译啊命令查询的任务分开,顾名思义,就是令(持久化)和查询职责进行分离,因为自己从来不针对
CQRS
进行了研究,也从不看过具体的演示,所以就边就未多说,但是自己当就是暨领域让设计之完美结合,后面有时机好研究下。

  说了那么基本上,那
Repository(仓储)职责到底是呀?可以如此回应:Repository,请服务好
Domain,而且只限服务为外(防止小三),他如什么您只要受啊,为什么?因为他是你大爷,跟在他来肉吃。

亚洲必赢app在哪下载 7

Domain Model(领域模型)重新规划

  领域模型是世界让设计的核心,这或多或少凡是毋容置疑的,那世界模型中的中坚是呀?或者说实现之凡什么?答案是工作逻辑,那事情逻辑又是啊?或者说怎么的“业务逻辑”才会叫真正含义及之事务逻辑,关于这题目,在达标亦然篇中残留如下:

领域模型到底该怎么统筹?你晤面看出,MessageManager
项目中的 User 和 Message
领域模型是那个贫血的,没有包含其他的作业逻辑,现在网上广大有关 DDD
示例项目多数乎存在这种情景,当然项目自并未事情,只是略的“CRUD”操作,但是只要是一些大型项目的错综复杂工作逻辑,该怎么去贯彻?或者说,领域模
型完成什么样的业务逻辑?什么才是当真的事务逻辑?这个问题充分要紧,后续探讨。

  什么才是当真的事情逻辑?CRUD
?持久化?还是如“GetUserByName、GetMessageByID”之类的询问,我个人感觉这些都非是实在意义上的工作逻辑(注意,是个人感觉),因为每个类别会有“CRUD”、持久化,并无特限于某平等种工作场景,像“GetUserByName、GetMessageByID”之类的询问才是询问,了解了上面
Repository 的感觉,你晤面发现这些查询工作应有是 Repository
做的,他是吗世界模型服务的。

  说了那么多,那什么才是真的含义及之政工逻辑?本人个人感觉改变世界模型状态或行为的业务逻辑,才会称之为真正含义上的事情逻辑(注意,是个人感觉),比如自己于
Repository
节点中说罢之一个示范:读取信息,要基于当前读书人与脚下信息之状态来安装当前消息之状态,如果手上读人为收件人和目前消息啊免念状态,就使拿当下消息状态设置为早已读,以前这业务逻辑的兑现是当应用层中:

 1         /// <summary>
 2         /// 查看消息
 3         /// </summary>
 4         /// <param name="ID"></param>
 5         /// <returns></returns>
 6         public MessageDTO ShowMessage(string ID, string isRead)
 7         {
 8             Message message = messageRepository.GetByKey(ID);
 9             if (isRead == "1")
10             {
11                 message.IsRead = true;
12                 messageRepository.Update(message);
13                 messageRepository.Context.Commit();
14             }
15             return Mapper.Map<Message, MessageDTO>(message);
16         }

  这种实现方式就会将应用层变为所谓的
BLL(业务逻辑层)了,正确的不二法门贯彻应有以 Domain
Model(领域模型)中,如下:

 1         /// <summary>
 2         /// 阅读消息
 3         /// </summary>
 4         /// <param name="CurrentUser"></param>
 5         public void ReadMessage(User CurrentUser)
 6         {
 7             if (!this.IsRead && CurrentUser.ID.Equals(ToUserID))
 8             {
 9                 this.IsRead = true;
10             }
11         }

  因为 MessageManager
这个类别的工作场景非常简单,很多都是简约的 CRUD
操作,可以抽离出真正的事务逻辑实在太少,除了上面阅读消息,还有即使是于发送信息之早晚,要基于发送用户称及纳用户称,来装信息之殡葬用户以及收受用户的
ID 值,这个操作以前俺们啊是于应用层中贯彻的,如下:

 1         /// <summary>
 2         /// 发送消息
 3         /// </summary>
 4         /// <param name="messageDTO"></param>
 5         /// <returns></returns>
 6         public bool SendMessage(MessageDTO messageDTO)
 7         {
 8             Message message = Mapper.Map<MessageDTO, Message>(messageDTO);
 9             message.FromUserID = userRepository.GetUserByName(messageDTO.FromUserName).ID;
10             message.ToUserID = userRepository.GetUserByName(messageDTO.ToUserName).ID;
11             messageRepository.Add(message);
12             return messageRepository.Context.Commit();
13         }

  改善以 Domain
Model(领域模型)中的兑现,如下:

 1         /// <summary>
 2         /// 加载用户
 3         /// </summary>
 4         /// <param name="sendUser"></param>
 5         /// <param name="receiveUser"></param>
 6         public void LoadUserName(User sendUser,User receiveUser)
 7         {
 8             this.FromUserID = sendUser.ID;
 9             this.ToUserID = receiveUser.ID;
10         }

  因为简单的 CRUD
操作不见面发生变化,而这些业务逻辑会经常发生变化,比如为消息被加载用户信息,可能现在加载的是
ID
值,以后或者会见补充加另的用户价值,比如:用户地理位置等等,这样咱们如果去修改领域模型就好了,应用层一点都无欲修改,如果还是事先的落实方式,你见面发现我们是须要修改应用层的,领域模型才是一个空壳。

Domain Service(领域服务)的投入

  关于 Domain
Service(领域服务)的定义,可以参见:http://www.cnblogs.com/netfocus/archive/2011/10/10/2204949.html#content_15,netfocus
兄关于世界服务讲解的深透,以下摘自个人感觉不错的片:

  • 世界受到的有的定义不绝符合建模为目标,即归类到实体对象或值对象,因为它们本质上就是是部分操作,一些动作,而无是物。这些操作还是动作往往会涉嫌到差不多个世界对象,并且需要协调这些领域对象共同完成这个操作还是动作。如果强行将这些操作职责分配为另外一个对象,则受分配的目标就是是负部分不拖欠担的职责,从而会导致对象的天职不显充分糊涂。但是因类的面向对象语言规定外性质或行为还必须放在对象中。所以我们用找相同栽新的模式来代表这种过多单对象的操作,DDD认为服务是一个异常自然的范式用来对号入座这种过多个目标的操作,所以就来了世界服务是模式。
  • 自己觉得模型(实体)与服务(场景)是对准天地的一样栽划分,模型关注世界的个人行为,场景关注世界的群体行为,模型关注世界的静态结构,场景关注世界的动态功能。这也称了具体中出现的各种气象,有动有静,有单独有合作。
  • 领域服务还有一个深重点之功能就是是可免领域逻辑泄露及应用层。

  另外还有一个用以说明应用层服务、领域服务、基础服务的职责分配的小示例:

  应用层服务

  1. 获输入(如一个XML请求);
  2. 出殡信息给世界层服务,要求其落实转帐的政工逻辑;
  3. 世界层服务处理成,则调用基础层服务发送Email通知;

  领域层服务

  1. 取源帐号和对象帐号,分别通报源帐号与对象帐号进行扣除金额及增金额之操作;
  2. 提供返回结果吃应用层;

  基础层服务

  1. 准应用层的要,发送Email通知;

  通过上述示范,可以非常清晰的理解应用层服务、领域服务、基础服务的任务,关于这些概念的知道,我相信 netfocus
兄是经过许多履得出的,因为未执行看这些概念和履了之后再行看这些概念,完全是不同之发。

  言归正传,为什么而在 Domain
Service(领域服务)?领域服务在我们之前筹 MessageManager
项目之时节并无,其实自己脑海中一直是生此概念,因为 Repository
的天职混乱,所以最后领域模型变得这么鸡肋,领域服务呢就无加入,那为何现在而加盟世界服务啊?因为
Repository
的任务分开,使得世界模型变成重中之重,因为应用层不跟 Repository
通信,应用层又不克直接与世界模型通信,所以才会生出天地服务的入,也得出世界服务之在。通过者概念的接头,你也许会见针对世界服务的意有得的掌握,首先领域服务没有状态,只有行为,他和
Repository
一样,也是也世界模型服务之,只不过他如一个外交官一样,需要和应用层打交道,用来协调领域模型和应用层,而 Repository
只是一个保姆,只是服务为世界模型。

  概念理解的基本上了,我们来拘禁一下具体的落实,以下是
MessageDomainService 领域服务中的一致段代码:

1         public Message ShowMessage(string ID,User CurrentUser)
2         {
3             Message message = messageRepository.GetByKey(ID);
4             message.ReadMessage(userRepository.GetUser(new User { Name = CurrentUser.Name }));
5             messageRepository.Update(message);
6             messageRepository.Context.Commit();
7             return message;
8         }

  这段代码表示查看消息,可以看来实际领域服务做的行事便是办事流程的操纵,注意是干活流程处理,并无是业务流程,业务流程
ReadMessage
是天地模型去做到的,领域模型的作用仅是协调。还生个谜就是,你晤面视在领域服务着运用及了
Repository,在咱们事先的教授中,Repository
不是单独服务为世界模型也?其实换个角度来拘禁,领域服务为得以看作是圈子模型的相同栽表现,Repository
现在重大提供的是询问集合和持久化,领域模型不可以自己操作,那这些干活儿只有领域服务去完成,关于这一点,就可以看出 Repository
的运用有点不极端合理,不知底用 CQRS
模式会无会见是外一样种植状态。

  另外,你晤面见到这同样段代码:messageRepository.Context.Commit();,这个是
Unit Of
Work(工作单元)的政工提交,这个工作是圈子服务如召开的吧?关于这或多或少凡起有疑难,在脚节点受到有解读。

MessageManager.Domain.Tests 的加入

  关于单元测试可以参考:http://www.cnblogs.com/xishuai/p/3728576.html,MessageManager.Domain.Tests
单元测试在头里的 MessageManager
项目受到连不曾增长,不是匪思添加,而是增补加了不要紧意思,为什么?因为之前的世界模型那么贫血,只是一些性和字段,那补加单元测试有啊意思?能测出来呀事物?当把工作聚焦在领域模型上之时段,对世界的单元测试将会十分之产生必不可少。

  来拘禁 DomainTest
单元测试的一部分代码:

 1 using MessageManager.Domain.DomainModel;
 2 using MessageManager.Domain.DomainService;
 3 using MessageManager.Repositories;
 4 using MessageManager.Repositories.EntityFramework;
 5 using NUnit.Framework;
 6 using System;
 7 using System.Collections.Generic;
 8 using System.Linq;
 9 using System.Text;
10 
11 namespace MessageManager.Domain.Tests
12 {
13     [TestFixture]
14     public class DomainTest
15     {
16         [Test]
17         public void UserDomainService()
18         {
19             IUserDomainService userDomainService = new UserDomainService(
20                 new UserRepository(new EntityFrameworkRepositoryContext()));
21             List<User> users = new List<User>();
22             users.Add(new User { Name = "小菜" });
23             users.Add(new User { Name = "大神" });
24             userDomainService.AddUser(users);
25             //userDomainService.ExistUser();
26             //var user = userDomainService.GetUserByName("小菜");
27             //if (user != null)
28             //{
29             //    Console.WriteLine(user.Name);
30             //}
31         }
32     }
33 }

  其实上面我贴的单元测试的代码有些不客观,你晤面视只是测试的持久化操作,这些应是基础层就的做事,应该由基础层的单元测试进行测试的,那世界层的单元测试测试的是呀事物?应该是天地模型中之事务逻辑,比如
ReadMessage 内的操作:

1         [Test]
2         public void MessageServiceTest()
3         {
4             IMessageDomainService messageDomainService = new MessageDomainService(
5                 new MessageRepository(new EntityFrameworkRepositoryContext()),
6                 new UserRepository(new EntityFrameworkRepositoryContext()));
7             Message message = messageDomainService.ShowMessage("ID", new User { Name = "小菜" });
8             Console.WriteLine(message.IsRead);
9         }

Application Layer(应用层)的协调?

Application
Layer(应用层):定义软件可以形成的劳作,并且指挥具有丰富意义的领域对象来化解问题。这个层所负责的职责对事情影响深远,对同任何系统的应用层进行互非常必要之层要保持简练。它不包括处理工作规则或文化,只是于下一样重叠中相互协作的小圈子对象协调任务、委托工作。在斯层次中未体现工作情况的状态,但反映用户还是程序的任务进度的状态。

  亚洲必赢app在哪下载以上是《领域让设计-软件基本复杂性应针对的道》书中有关应用层给来之概念,应用层是挺薄的同样重叠,如果您的应用层很“厚”,那您的应用层设计虽自然起了问题。关于 Application
Layer(应用层)的运,正而 Eric Evans
所说:不包处理事务规则或文化,只是吃下一样重叠中相互协作的小圈子对象协调任务、委托工作。重点就是是:匪分包业务逻辑,协调任务。

  如果按自己的接头去规划应用层,很可能会见如本人一样将其化工作逻辑层,所以在计划过程被自然要谨记上面两点。不带有业务逻辑很好明,前提是设清楚啊才是当真的事务逻辑(上面来证),后面同样句协调任务而是什么意思啊?在证明遭到后还有平等句:在此层次中无反映工作情况的状态,但反映用户还是程序的天职进度的状态。也就是是办事流程的操纵,比如一个生育工艺流程,应用层的企图就比如是者生育流程的控制器,具体生产什么它不需要管理,它若可以配零件然后进行重组展示受用户,仅此而已,画了一样摆放示意图,以便大家的亮:

亚洲必赢app在哪下载 8

  另外,应用层因为一旦指向表现层以及领域层进行任务协调,这中间会涉嫌到多少的对象转换,也尽管是
DTO(数据传对象),有关 DTO 的定义和 AutoMapper
的施用可参照:http://www.cnblogs.com/xishuai/tag/DTO\_AutoMapper,这些工作是当应用层中展开处理的,就比如生产流水线,组装了产品晚,需要针对其开展包装才会拓展亮:

 1         /// 对应用层服务进行初始化。
 2         /// </summary>
 3         /// <remarks>包含的初始化任务有:
 4         /// 1. AutoMapper框架的初始化</remarks>
 5         public static void Initialize()
 6         {
 7             Mapper.CreateMap<UserDTO, User>();
 8             Mapper.CreateMap<MessageDTO, Message>();
 9             Mapper.CreateMap<User, UserDTO>();
10             Mapper.CreateMap<Message, MessageDTO>()
11                 .ForMember(dest => dest.Status, opt => opt.ResolveUsing<CustomResolver>());
12         }
13         public class CustomResolver : ValueResolver<Message, string>
14         {
15             protected override string ResolveCore(Message source)
16             {
17                 if (source.IsRead)
18                 {
19                     return "已读";
20                 }
21                 else
22                 {
23                     return "未读";
24                 }
25             }
26         }

Unit Of Work(工作单元)工作范围及实现?

  关于 Unit Of
Work(工作单元)的定义好参见:http://www.cnblogs.com/xishuai/p/3750154.html。

Unit Of
Work:维护让工作工作影响的靶子列表,并协调变化的写入和出现问题之缓解。即管理对象的
CRUD 操作,以及相应的作业以及出新问题相当。Unit of Work
是因此来解决世界模型存储和转工作,而这些数据层业务并无属世界模型本身有的。

  工作单元的定义在《企业应用架构模式》中吗发证实,定义如下:维护被工作工作影响的目标列表,并协调变化之写入和出现问题之化解。概念的接头并没有呀问题,我怀念发挥的凡工作单元的干活范围与如何实现?先说生办事范围,我们看下我曾经画的均等张工作单元的流程图:
亚洲必赢app在哪下载 9

点击查看大图

  从示意图中得以视,工作单元的限量是压
Repository 的,也就是说工作单元是无力回天跨 Repository
提交业务之,只能当与一个囤内管理事务之一致性,就比如我们应用的
using(MessageManagerDbContext context = new MessageManagerDbContext())
一样,只是局限为这 using
块,我早已在领域层的单元测试中召开如下测试:

 1         [Test]
 2         public void DomainServiceTest()
 3         {
 4             IUserDomainService userDomainService = new UserDomainService(
 5                 new UserRepository(new EntityFrameworkRepositoryContext()));
 6             IMessageDomainService messageDomainService = new MessageDomainService(
 7                 new MessageRepository(new EntityFrameworkRepositoryContext()),
 8                 new UserRepository(new EntityFrameworkRepositoryContext()));
 9             List<User> users = new List<User>();
10             users.Add(new User { Name = "小菜" });
11             users.Add(new User { Name = "大神" });
12             userDomainService.AddUser(users);
13             messageDomainService.DeleteMessage(null);
14         }

  我当 MessageDomainService
中付出业务,因为前面 UserDomainService
已经补给加了用户,但是并没增长用户成功,工作单元中之 Committed 值为
false,其实关于工作单元范围之题材,我现连没明白的想法,现在凡是受制在存储中,那提交的事体操作就亟须放在领域服务受到,也就算是:messageRepository.Context.Commit();,但是又会看这样聊不成立,工作单元应该是贯通整个项目之,并不一定局限在某某平等囤积中,而且工作之处理液应该在应用层中,因为马上是外的行事,协调工作流的处理。

  如果这种思考是无可非议吧,实现起来着实发生把难度,因为今
ORM(对象关联映射)使用的是
EntityFramework,所以工作单元的实现是杀粗略的,也就是下 SaveChanges()
方法来交给业务,我在《企业应用架构模式》中观看工作单元的贯彻,书中列有了一个简单的例子,还只是聚众的保管,如果未应用有
ORM 工具,实现起来便不仅是 SaveChanges()
一段落代码的事了,太局限为技术了,确实是只问题。

  这同节点的情节只是提出有问题,并未发出缓解之点子,希望后面可以探讨下。

本发布

  MessageManager
项目解决方案目录:

亚洲必赢app在哪下载 10

  • GitHub
    开源地址:https://github.com/yuezhongxin/MessageManager
  • ASP.NET MVC
    发布地方:http://www.xishuaiblog.com:8081/
  • ASP.NET WebAPI
    发布地点:http://www.xishuaiblog.com:8082/api/Message/GetMessagesBySendUser/小菜

  注:ASP.NET WebAPI
暂只有含:获取发送放消息列表和收获接收方消息列表。

  调用示例:

  • GetMessagesBySendUser(获取发送方):http://www.xishuaiblog.com:8082/api/Message/GetMessagesBySendUser/用户名
  • GetMessagesByReceiveUser(获取接受方):http://www.xishuaiblog.com:8082/api/Message/GetMessagesByReceiveUser/用户名

  WebAPI 客户端调用可以参考
MessageManager.WebAPI.Tests 单元测试项目蒙之以身作则调用代码。

  注:因为 GitHub 中针对 MessageManager
项目进展了翻新,如果想看上一版本,下载地址:http://pan.baidu.com/s/1gd9WmUB,可以和水土保持版本对照下,方便学习。

  另外,《领域让设计.软件基本复杂性应本着之志》Word
版本,下载地址:http://pan.baidu.com/s/1bnndOcR

后记

亚洲必赢app在哪下载 11

  这首博文不知不觉写点儿上了(周末),左手吗来接触未那么巧了,如果重新写下来,大家呢该骂我了(看得最好艰难),那就算做一下总结吧:

  关于世界模型的计划,我个人感觉是世界让设计着极其难的部分,你见面盼眼前我于 MessageManager
项目面临仅出零星个方式,一部分原因是工作场景太简单,另一样有的由或是自己设计之匪客观,复杂性业务场景的小圈子模型是大半个类之间协调处理,并会发生有设计模式的参加,是一对一复杂的。

  需要留意的一些是,本篇以上内容并无是叙
Domain
Model(领域模型)到底哪贯彻?而是什么聚焦领域模型?只有聚焦于世界模型上,才能够把世界模型设计之更合理,这为亏下一致步用探索的内容。

  要么那么句话,真正懂以及应用
DDD(领域让设计)的绝无仅有办法,个人感觉还是“迭代”:不断的夺执行,不断的错过体会。不成立那即便推倒重建,再无客观那就是推倒重重建。。。

  如果您道本篇文章对你所有助,请点击右侧下“推荐”,^_^

  参考资料:

  • http://www.cnblogs.com/dudu/archive/2011/05/25/repository_pattern.html
  • http://www.cnblogs.com/1-2-3/category/109191.html
  • http://www.jdon.com/ddd.html
  • http://www.cnblogs.com/daxnet/archive/2009/03/31/1686984.html
  • http://www.cnblogs.com/netfocus/archive/2011/10/10/2204949.html
  • http://www.oschina.net/question/12_21641

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2018 亚洲必赢app官方下载 版权所有