
这一说法是否自相矛盾呢Martin Fowler在PoEAA一书中给了一个有力的解释我们把三层架构等除了领域驱动之外的架构方式都可以归纳为以数据为中心的架构方式在图中是黑色的粗实线领域驱动设计在图中是绿色的粗实线。当软件在开发初期以数据驱动的架构方式非常容易上手但是随着业务的增长和项目的推进软件开发和维护难度急剧升高。领域驱动设计则在项目初期就处在一个比较难以上手的位置但是随着业务的增长和项目的推进软件开发和维护难度平滑上升。这幅图形象的解释了领域驱动设计和传统的软件架构模式两者在软件开发过程中解决复杂性之间的差异。领域驱动设计的核心是什么顾名思义领域驱动设计的核心是领域模型这一方法论可以通俗的理解为先找到业务中的领域模型以领域模型为中心驱动项目的开发。而领域模型的设计精髓在于面向对象分析在于对事物的抽象能力一个领域驱动架构师必然是一个面向对象分析的大师。在面向对象编程中讲究封装讲究设计低耦合高内聚的类。而对于一个软件工程来讲仅仅只靠类的设计是不够的我们需要把紧密联系在一起的业务设计为一个领域模型让领域模型内部隐藏一些细节这样一来领域模型和领域模型之间的关系就会变得简单。这一思想有效的降低了复杂的业务之间千丝万缕的耦合关系。下图为“以数据为中心的架构模式”表和表之间关系错综复杂下图是“领域模型”领域和领域之间只存在大粒度的接口和交互初期学习DDD的朋友一定不会错过Eric Evans写的《领域驱动设计软件核心复杂性应对之道》这本书名气很大也是很多人入门领域驱动设计的首选读物这本书提到了领域驱动设计中的一些概念RepositoryDomainValueObject等。但是初学者有可能得出一个错误的结论有人误认为项目架构中加入***Repository***Domain***ValueObject就变成了DDD架构。如果没有悟出其精髓就在项目中加入这些概念那充其量也不过是个三层架构反之对于一个面向对象分析的高手而言不使用这些概念也可以实现领域驱动设计。以IUserRepository这样一个接口定义为例1234567publicinterfaceIUserRepository : IRepositoryUser{//Whats this?ListRule GetRules(int id);//....}一个IUserRepository是一个Repository他只能以User聚合根为单位进行操作。方法ListRule GetRules(int id)将此Repository打回了原形这不再是一个Repository这是一个DAL。正确的实现方式1234567891011121314publicclassUser:AggregateRoot{privateListRule GetRules(){returnnull;}publicvoid ApproveRequest(Request request){varrules user.GetRules();//......//如果有权限就批准}}这段代码体现了User作为一个领域模型他拥有自己的职责和能力。如何开始实践领域驱动设计正如本文通篇所说领域驱动设计讲究的是领域模型的分析和对事物的抽象从来没有提起过数据如何存取这个话题言下之意在领域驱动设计中我们不关心过数据如何存取怎么样写linq效率高使用懒加载还是include这些实现细节会将你带入传统的三层架构模式中。在领域驱动设计中要先设计领域模型接着写Domain逻辑至于数据库仅仅是用来存储数据的工具。使用database first那不叫领域驱动设计很明显你先设计的表结构所以应该叫数据库驱动设计更为准确。更不要引入数据库独有的技术例如触发器存储过程等。数据库除了存储数据外其余一切逻辑都是Domain逻辑。我们不妨以大家都比较熟悉的医院门诊看病流程举个例子看看如何开始实践领域驱动设计我们暂且认为一个门诊看病流程就是一个完整的领域模型此时你要忘掉数据库不要再想表结构如何设计而是就这一领域模型进行抽象1234567891011121314151617181920212223242526272829303132333435363738394041publicclassOutPatientProcess:AggregateRoot{publicRegistration _registration { get;privateset; }//挂号单privateListExamination _examinations;publicIReadOnlyListExamination Examinations _examinations.AsReadOnly();//化验单publicPrescription Prescription { get;privateset; }//处方publicDateTime ConsultaionTime { get;privateset; }//接诊时间publicDoctor Doctor { get;privateset; }//接诊医师//开始一个门诊治疗过程publicvoid StartProcess(Registration registration){_registration registration;InquireSymptoms();WriteOutExamination();WritePrescription();}//询问病人病情publicvoid InquireSymptoms(){}//开立化验单privatevoid WriteOutExamination(){_examinations.Add(newExamination());}//填写处方privatevoid WritePrescription(){}