鸿 网 互 联 www.68idc.cn

当前位置 : 服务器租用 > .net技术 > asp.net编程 > >

.NET领域驱动设计初尝(三:穿过迷雾走向光明)

来源:互联网 作者:佚名 时间:2013-10-23 09:04
开篇介绍在开始这篇富有某种奇妙感觉的文章之旅时我们先短暂的讨论一下关于软件开发方法论的简要:纵观软件开发方法论,从瀑布模型、螺旋模型、RUP(统一软件开发
开篇介绍

能被我们接受并且愿意花时间花精力去学习去实践它,因为它发现了复杂软件设计问题的核心解决方法

基础数据与业务数据之间的关联需要很小心,我们要衡量好之间的关系。当我们识别出基础数据之后在首次进行建模的时候为了合理的表达领域模型的完整性会将其关联的很紧密,在团队中进行交流评审的时候都是很有帮助的,到了后面重构阶段一定会将庞大的蜘蛛网合理的拆开形成精简的聚合模型;

本节想强调的是正确的识别出领域中的“基础数据”和“业务数据”,让后将其合理的关联来表达领域模型;

1.3.3】模型在数据库中的主外键关联问题

当模型落实到代码上的时候我们就要考虑如何将模型在关系型数据库中存储的问题,当然你可以存放在任何地方,但是不同的数据存储方式会对你的模型有一定程度的影响或者说会影响你建模的细节思路,这是需要平衡的;有人会说:“模型的创建应该完全不用去考虑到底如何持久化”,难道真的是这样的吗?我通过实践证明问题恰恰相反,当你在建模的时候如果不懂的技术实现那么就会产生像DDD书中所说的分析与设计之间的裂缝,分析人员分析出来的模型根本无法在真实的技术环境下实现;难道你还会说:”分析的时候完全不用去考虑到底如何实现“,这就是DDD所说的复杂软件开发问题所在;

在目前情况下普遍认为分析人员大于程序员,他们占主导地位,想当然的去搜集业务然后交给你实现,当他让你实现一个很别扭的功能的时候其实你完全可以用自己的专业意见来改善的很平滑,但是由于工作职责的不同他们并不是很懂的技术实现的细节所以问题就在这里;

【这不是我结论,在《领域驱动设计.软件核心复杂性应对之道》一书中,Eric Evans 是这么定义的,详见书中第7章;问题确实如此;】

这里我们只讨论面向关系型数据库的存储方式;聚合是一类实体的集合,会有一个“带头”的实体也就是聚合根,我们对它的操作需要很小心,比如:当你插入一个聚合根时会把聚合根所涉及的一些附属模型都插入,这个时候就是错误的;这个时候如果没有很好的数据访问组件来支持的话我们很难保证数据的一致性,后面我会专门写一个系列针对Microsoft.EntityFramework的文章,因为目前.NET平台稳定的实体框架就属实体框架EF了;

按道理我们的聚合是一个带有根的实体集,他们被逻辑划分到一个业务范围中,比如【FieldExamination】每场考试聚合,当我们查询有关一场考试信息的时候会关联出它所附属的一些其他信息,这是查询没有问题,但是当我们进行删除、更新、添加的时候问题没有那么简单了,当然是可以避免了这里跟大家分享一下需要注意的地方;

public class FieldExamination:EntityRoot { public string FId{get;set;} public Datetime BeginTime{get;} public Datetime ProcessTime{get;} //获取本场考试的试卷 public GetCurrentExBook(string stuId){//……} //本场考试的负责人 public Employee Principal{get;} public Subject CurrentSubject{get;} } public class FieldExaminationRepostiroy:Repository<FieldExamination> { public FieldExamination GetById(string id){//……} }

上述FieldExamination实体没有任何问题,恩 看起来是没有问题;当我们对数据库进行查询的时候是没问题的,会顺利的得到FieldExamination实体确实很方便,这也是DDD的精神所在;但是当我们进行对象的插入的时候问题来了,通常我们对实体进行创建的时候是会通过一个专门的Factory来创建,这个对象是一个完整的,包含了基本的属性信息,比如这里的FieldExamination实体创建的时候是肯定要知道它的负责人是谁并且本场考试的科目是什么,我们会对相关的属性进行赋值,那么这个时候进行插入的时候就会将相关的属性插入到属性所要持久化的表中去,这里也就是会将Principal属性插入到Employee表中去,那么就是错误的,同样其他的属性都是这种情况;

那么到底如何解决,其实就是通过“标量属性”来解决,这个时候实体会增加一些属性所对应的“属性字段”如:

public class FieldExamination:EntityRoot { public string FId{get;set;} public Datetime BeginTime{get;} public Datetime ProcessTime{get;} //获取本场考试的试卷 public GetCurrentExBook(string stuId){//……} //本场考试的负责人 public int PrincipalId{get;}//查询的时候这个属性不需要关心 public Employee Principal{get;} public int CurrentSubjectId{get;}//查询的时候这个属性不需要关心 public Subject CurrentSubject{get;} }

还无法很好的在我们系统中实现;这本身就是静态语言的一个问题,静态语言的所有逻辑在编译时就已经确定,不管你是直译式还是中间式的编译过程,本身语言的设计就是这种静态思想;

【FieldExamination】是表示【每场考试】、【Employee】是表示【员工】、【Subject】是表示【课程类别】枚举,目前我们看的见就这三个;

上面曾说过蓝色背景的模型是潜在的模型,这里我们需要精简的是【每场考试FieldExamination】模型,上图中可以看到以它为聚合的关联有四个,我们就来看【Employee】模型,它是表示所有的学校员工信息,从【FieldExamination】到【Employee】有一个Principal聚合,对于每场考试我们通常都是有一个负责人的,在考试期间可能会去巡查考试纪律包括站考老师是否真的严格站考;好像没有问题啊,就应该有一个复杂人才对啊,但是【Employee】还关联一些其他模型:

4.5图

这样下去一个链接一个,牵一发而动全身,根本无法使用就连重构都很困难;那么我们如何寻找要断开的链接点呢?我们需要考虑【聚合】的范围,在上图中的【FieldExamination】中,我们如果需要关联本场考试的负责人是谁那么在当【FieldExamination】被读进到内存的时候就被一起关联出来,但是当我们考虑真实的业务需求的时候到底需不需要将【Employee】带出来,【Employy】被带出来的时候就要牵扯到【Employee】所涉及的关联;

网友评论
<