- 相关推荐
经典的领域驱动设计在代码实践方面的心得体会
创建领域对象采用构造函数或者工厂,如果用工厂时需要依赖于领域服务或仓储,则通过构造函数注入到工厂;领域服务可以依赖仓储或聚合根;
一个聚合根配备一个仓储;
仓储应理解为一个在内存中维护一系列聚合根的集合;
一个聚合有一个聚合根,聚合根也是一个Entity,聚合内还有其他Entity和Value Object;
仓储提供的方法应该总是接受聚合根或返回聚合根,不能返回聚合内的其他Entity或Value Object;
聚合内的非跟的Entity以及Value Object之间不要相互引用,聚合内的所有Child可以对根Entity持有引用,如果一个Child Entity需要和另外一个Child Entity交互,则因该通过聚合根完成;
聚合根与聚合根之间应避免直接对象引用,而应该采用ID关联;聚合根与聚合根之间的关系不像聚合内的Entity之间这么强烈内聚,它们之间仅仅是某种比较弱的关联关系,每个聚合根都有其独立的生命周期;
聚合根之间通过ID关联的好处是:不会因为Load一个聚合根而把其他关联的聚合根一起Load出来,这样也避免了Load一个聚合根会把整个数据库Load出来的风险;
我们应该尽量减少关联,尽量做到单向关联,只保留确实需要处理的经常需要用到的遍历方向的关联;
如果一个操作仅由一个聚合根就可以完成,那么直接调用该聚合根完成即可;
如果一个操作我们会遇见到会由多个聚合根相互协作完成,那么需要为该操作建立领域服务,在领域服务中以过程化的方式来一步步调用相关的聚合根完成整个业务操作;
切忌不要因为领域服务的引入让聚合根变得贫血,聚合根应该有职责还是必须要由聚合根来承担;
聚合根内不要依赖领域服务或仓储,如果你发现一个聚合根的职责需要依赖于某个领域服务或仓储来帮忙完成一些其他的逻辑(像判断业务规则之类),那么通常你要考虑这个职责不应该由该聚合根来承担,而应该建立合适的领域服务来承担;聚合根的主要职责是管理其内聚的所有Child Entity或Value Object的业务完整性;
领域驱动设计时,为对象分配职责时,可以参考信息专家模式:将职责分配给拥有执行该职责所需信息的人;如果一个聚合根看起来拥有执行某个职责所需的信息,但没包含全部所需信息,此时则不应该将该职责分配给该聚合根,因为强行分配给它,会导致该聚合根没有内聚性,因为势必会依赖于其它的领域对象或领域服务或仓储;
聚合内的所有实体和值对象应该总是一起被取出来一起被保存,因为一个聚合是一个数据持久化的单元,不需要考虑将整个聚合根取出来有性能问题,因为任何一个聚合根都有明确的边界。目前的内存缓存框架都已发展的比较成熟,性能已经不是问题;如MongoDb,MemCache,NoSQL,等等;
不要给仓储提供一些目的是为了为界面提供显示数据的接口,仓储提供的所有接口仅为领域模型使用;
要学习CQRS架构,要知道我们应该将应用程序的业务逻辑处理部分(即用户命令响应部分)和查询部分分离;我们应该用两个不同的技术来实现这两个部分的实现;用DDD领域模型来实现命令部分;用最快的查询引擎来实现查询部分;
如果要采用CQRS架构,我们需要考虑一个成熟可靠的底层框架,否则很容易导致命令端产生的领域对象的状态无法同步(后者丢失)到查询端的存储中;
领域服务依赖仓储时,工厂依赖于领域服务或仓储时,都因该采用构造函数注入的方式,这样可以避免领域模型中不会出现DependencyResolver.Resolve<T>()这样的语句;
不要把仓储理解为DAO,仓储属于领域模型的一部分,代表了领域模型向外提供接口的一部分,而DAO是表示数据库向上层提供的接口表示;
领域对象上的属性可以具有get和set,因为我们平时所理解的对象不是真正的对象,而是某个事实的描述,比如图书管理系统中的一个Book对象,表示图书管中放着一本书,然后该书可能有一个入库时间。现实生活正的话,书本的入库时间绝对不可能变化,但是软件中的Book因为不是真正的现实生活中的书本,而只是表示图书馆中有一本书这个事实的描述,我们当然可以修改这个事实,因为我们可能因为之前在书本入库时所输入的入库时间是错的,需要修改该入库时间,此时就有提供set的必要了。所以,理论上任何一个Entity,除了ID之外,其他所有属性都可以更改,因为这些属性并不表示现实生活中的真正对象的特征,而仅仅只是对一个事实的描述;刚开始Book对象对书本入库这个事实的描述可能有问题,此时我们就需要修改该Book的属性;我想这个例子已经充分说明为什么可以提供get和set了;
不要总是零散的不加任何分组的设计Entity的属性,因为有些属性在逻辑上或业务上就是内聚的,代表一个完整的概念,比如Country,Province,City,Town,Street,等这些属性表示一个地址的信息,此时我们应该设计一个Address对象来表示该地址信息,此时该Address就是一个值对象。所以我们在设计Entity的属性时,要好好想想,哪些子属性其实在业务上是一个完整的概念,此时我们就需要考虑将这些相关的属性设计为一个值对象;
切忌值对象必须是只读的,值对象之所以叫值对象最主要的是因为它表示一个值,而不是一个对象;值是不会变化的,是一个明确含义的不变的事物,比如3表示一个值,表述数量是3,3永远不能变化;所以说,世界之所以存在,是因为有这些永恒不变的值对象的存在;我们只要把值对象理解为3,“abcd”这样的永恒不变的值就行了;
不要让领域模型去模拟现实,模拟用户(软件使用者)与领域模型交互的过程;领域模型要实现的应该是用户的需求,领域模型中不应该包含用户的成分,想想只有空杯子才能装水的道理,即无为以之用的道理就明白了;所以,我们在设计领域模型时首先要明白领域模型要完成的事情是什么;这方面,多看看用例图,就知道软件该做的事情了,推荐大家看的书是:Craig Larman写的《UML和模式应用》一书,非常经典;
暂时就写这么多吧,以后想到什么再补上,呵呵。
【经典的领域驱动设计在代码实践方面的心得体会】相关文章:
幼儿园语言领域方面的教案(精选23篇)10-06
活动设计健康领域教案12-19
活动设计科学领域教案08-26
设计方岗位职责04-17
幼儿活动设计健康领域教案02-16
活动设计健康领域教案(7篇)12-24
活动设计健康领域教案7篇12-20
健康领域心得体会02-20
任务驱动型作文05-10
活动设计健康领域教案通用7篇12-27