最近看了《领域驱动设计:软件核心复杂性应对之道》,从字面上来看领域驱动就是解决软件复杂性问题的;然而领域驱动设计的门槛很高,没有很深厚的面向对象编码能力几乎不可能实践成功。Martin Fowler在PoEAA一书中给了一个有力的解释:
我们把三层架构等除了领域驱动之外的架构方式都可以归纳为以数据为中心的架构方式,在图中是黑色的粗实线;
领域驱动设计在图中是绿色的粗实线。
- 当软件在开发初期,以数据驱动的架构方式非常容易上手,但是随着业务的增长和项目的推进,软件开发和维护难度急剧升高。
- 领域驱动设计则在项目初期就处在一个比较难以上手的位置,但是随着业务的增长和项目的推进,软件开发和维护难度平滑上升。
这幅图形象的解释了领域驱动设计和传统的软件架构模式两者在软件开发过程中解决复杂性之间的差异。
所谓领域驱动设计,可以从三个方面理解:
领域:可以理解为就是一个问题域,有边界,只要是同一个领域,那问题域就相同,我们做任何一个软件系统,都是有原因的,否则就没必要做这个系统,而这个原因就是我们遇到的问题。一个超市系统就可以看成是一个领域,其他的和超市相似需求系统就能属于同一个领域,因为每个系统都要有商品的显示,顾客购买商品结账等功能;
设计:主要是领域模型的设计,每个领域都对应着一个模型设计,每一个领域,都有一个对应的领域模型,领域模型能够很好的帮我们解决复杂的业务问题;
驱动:领域驱动领域模型设计,领域驱动代码实现;
领域驱动设计(DDD)告诉我们的最大价值我觉得是:当我们要开发一个系统时,应该尽量先把领域模型想清楚,然后再开始动手编码,这样的系统后期才会很好维护。
总结:
领域就是问题域,有边界,领域中有很多问题;
任何一个系统要解决的那个大问题都对应一个领域;
通过建立领域模型来解决领域中的核心问题,模型驱动的思想;
领域建模的目标针对我们在领域中所关心的问题,即只针对核心关注点,而不是整个领域中的所有问题;
领域模型在设计时应考虑一定的抽象性、通用性,以及复用价值;
通过领域模型驱动代码的实现,确保代码让领域模型落地,代码最终能解决问题;
领域模型是系统的核心,是领域内的业务的直接沉淀,具有非常大的业务价值;
技术架构设计或数据存储等是在领域模型的外围,帮助领域模型进行落地;
开发系统要理解零领域,拆分领域,细化领域
领域知识软件设计的一部分,还有更多的设计 如:架构设计,数据库设计等;
领域驱动中的一些概念:
实体:实体所包含的不单止是一连串的属性,更重要的是与事件的联系,在一个生命周期中环境的变化与事件发生,将引起实体内部产生变化。好像在实体Order里面,Person的积分(Point)和OrderItem的价格(Price)都会直接影响总体价格(TotalPrice)的大小,而总体价格也会影响到运费Freightage的多少等等。在Order实体的一切,都会受到Person、OrderItem等这些外部因数的影响,这样的对象被视为实体。在不同的时刻,实体会有不同的状态,所以在开发过程中我们需要为实体加上一个“标识符”来区分对象的身份,它是实体的生命周期里的唯一标志。
值对象:当所用到的对象只有属性而没有其他逻辑关系的时候,我们就可以把它视为是值对象。值对象没有状态,也不需要有 “标识符”。在多数情况下它可以作为一个属性存在于一个实体的内部。一般情况下值对象的属性是不可改变的,当需要更改属性时,可以把整个对象删除,然后重新加入一个新对象。
服务:当实体之间存在某些操作,它们并不单一地附属于某一个实体,而是跟多个实体都有关联的时候,就可以使用服务来封装这些操作。值得注意的是服务并非单独指Web Service, 也并非单单存在于领域层,而是在各个层当中都会存在服务,每一层的服务都有着不同的职能。在基础结构层服务可能是用于构建身份验证、电子邮件、错误处理等等操作;在领域层,服务更多时候是一种操作,它用于协调多个实体之间的关系,处理各类的业务问题;在应用层(特别是在分布式开发系统内),服务多以Web Service、TCP/IP套接字、MSMQ等等方式实现,服务在此处会作为一个与外界通讯的接口;
Repository:是把持久化对象转换成领域模型的一种方式,可用于获取、更新持久对象并管理它们的生命周期。它使应用程序与持久化技术实现解耦,程序无需受制于使用Oracle还是MySql数据库,也不会受到Hibernate、LINQ、ADO.NET等数据层的约束,使开发人员可以把注意力集中到领域模型当中。
领域驱动的学习是一个漫长的过程,所以在今后的项目实战中要不断总结,理解。