> 领域驱动设计 - 思想体系 - DDD 是一种开发思想体系,旨在管理为复杂问题域编写的软件的创建和维护工作。 - 专注领域要高于其他一切需求。 - DDD是模式、原则和实践的集合,可以被用到软件设计以管理 - 模式类型 - 战略模式:对任何应用程序都有用 重点提炼问题域(核心子域)->塑造应用程序架构 - 战术模式:用于实现富领域模型(只当模型在领域逻辑做够丰富时才有用) - 实践原则 - 专注于核心领域 强调在核心子域付出最多努力的需要 - 通过协作学习 开发团队与业务专家的协作 - 通过探索和实验来创建模型 - 通信 公共语言(UL) - 理解模型的活用性 语言边界,避免歧义 - 让模型持续发展 持续致力与知识提炼 > 通用语言 - 抛开DDD 想到通用语言首先想到英语 特点:1)简单易学 2)使用效率高 3)国际通用 - 概念:通过团队交流达成共识的能够准确传递业务规则的简单的语言 - 价值 解决了交流障碍问题,使领域专家和开发人员协同合作 > 领域(重在范围的界限) - 本质 :可以理解为 就是一个问题域,只要是同一个领域,那问题域就相同。所以,只要我们确定了系统所属的领域,那这个系统的核心业务,既要解决的关键问题、问题的范围边界就基本确定了。 - 与传统开发过程的区别在于 DDD注重领域建模 - 领域拆分: 子域、核心域、通用子域、支撑子域 - 举个例子(比如创建个电商网站 需要涉及的业务。商品、用户、订单、报价、支付、物流、保修相关业务) - 大致拆分:商品子域、用户子域、销售子域、订单子域、支付子域、物流子域、维修子域 - 确定核心域:开发电商网站的目的是为了寻求推广和销售利润的最大化。所以核心域就是销售子域。 - 通用子域:服务服务于整个业务领域。-》日志子域 可以为该网站提供一个日志系统,来记录一些日志。我们可以设计一个日志子域来供其他子域使用。 - 支撑子域:作用于业务系统的某些重要业务而非核心业务,它关注于业务的某一方面,来支撑完善业务系统。 - 我们划分的子域中除了销售子域,其他都可以说是支撑子域。 - 比如物流子域,就是专注于物流相关业务,支撑着订单发货以及物流跟踪的重要流程。 > 界限上下文 - 可拆分为两个词,界限和上下文。 界限是指一个界限,具体的某一个范围。 上下文可理解为语境。 - 例子 还是上述(电子商务)例子 - 在销售子域和商品子域中就是商品 - 在物流子域中特质货物,只关注部分属性 - 命名 领域名+上下文 销售上下文 物流上下文 > 领域模型 - 概念:描述正在解决的问题及提出的解决方案 - 特征: - 综合了系统分析和设计 - 语言、模型、代码 三者紧密绑定 - 可以通过UML类图来展示 - 例子 在线商城案例 ``` Customer public class Customer { public int Id{get;set;} public string Name{get;set;} public string BillingAddress{get;set;} public string DeliveryAddress{get;set;} Public string LoginName{get;set;} public string LoginPassword{get;set;} public string DayOfBirth{get;set;} } order public class Order { public int Id{get;set;} public string CreatedDate{get;set;} public string CreatBy{get;set;} } OrderLine public class OrderLine { public int Id{get;set;} public string Quantity{get;set;} public string Discount{get;set;} } Category public class Category { public int Id{get;set;} public string Name{get;set;} public string Description{get;set;} } CreditCard public class CreditCart { public int Id{get;set;} public string Number{get;set;} public string HolderName{get;set;} public string ExpirationDate{get;set;} } Item public class Item { public int Id{get;set;} public string Name{get;set;} public string Description{get;set;} public string PurchasePrice{get;set;} public string SalesPrice{get;set;} } ``` > 实体 (Entity) - 概念: 唯一身份标识+可变性[状态(属性)+行为(方法或领域事件或领域服务)] - 唯一标识: 针对上述例子 抽象出User实体 要定义其唯一标识。 - 性格、外貌、昵称、身份证号都可以是User的属性,但为了确保标识的稳定性,智能用身份证号设为唯一身份标识。 - 唯一标识的类型 - 一个简单的应用程序里,一个int类型的自增Id就可以作为唯一标识。优点就是占用空间小,查询速度快。 - 而在一些业务当中,要求唯一标识有意义,通过唯一标识就能识别出一些基本信息,比如支付宝的交易号,其中就包含了日期和用户ID。这种就属于字符串类型的标识,这就对唯一标识的生成提出了挑战。 - 唯一标识的生成时机 - 即时生成,即在持久化实体之前,先申请唯一标识,再更新到数据库。 - 延迟生成,即在持久化实体之后。 - 委派标识和领域标识 - 基于领域实体概念分析确定的唯一身份标识,我们可以称为领域实体标识 - 实现层超类型 - 定义层超类型接口 ``` public interface IEntity { } public interface IEntity : IEntity { TPrimaryKey Id { get; set; } } ``` - 实现层超类型 ``` public class Entity : Entity, IEntity { } public class Entity : IEntity { public virtual TPrimaryKey Id { get; set; } public override bool Equals(object obj) { if (obj == null || !(obj is Entity)) { return false; } if (ReferenceEquals(this, obj)) { return true; } var other = (Entity) obj; var typeOfThis = GetType(); var typeOfOther = other.GetType(); if (!typeOfThis.GetTypeInfo().IsAssignableFrom(typeOfOther) && !typeOfOther.GetTypeInfo().IsAssignableFrom(typeOfThis)) { return false; } return Id.Equals(other.Id); } public override int GetHashCode() { return Id.GetHashCode(); } public static bool operator ==(Entity left, Entity right) { if (Equals(left, null)) { return Equals(right, null); } return left.Equals(right); } public static bool operator !=(Entity left, Entity right) { return !(left == right); } } ``` - 可变性 - 实体的状态 eg:订单状态:未支付、正常、已发货、关闭 - 实体的行为 eg:订单行为:支付、发货、关闭 > 值对象 - 概念:值+对象=》将一个值用对象的方式进行标书,表达一个具体的固定不变的概念 - 值特征: - 表示一个具体的概念 - 通过值得属性对其识别 - 属性判断 - 固定不变 - 案例分析(购物网站都会维护客户收货地址信息来进行发货处理,一个地址信息一般主要包含省份、城市、区县、街道、邮政编码信息。) - 地址是一个值,不会随着时间而变化,它包含了地址所需要的完整属性(省份、城市、区县、街道、邮政编码) ``` public class Address { /// /// 省份 /// public string Province { get; private set; } /// /// 城市 /// public string City { get; private set; } /// /// 区县 /// public string County { get; private set; } /// /// 街道 /// public string Street { get; private set; } /// /// 邮政编码 /// public string Zip { get; private set; } public Address(string province, string city, string county, string street, string zip) { this.Province = province; this.City = city; this.County = county; this.Street = street; this.Zip = zip; } public override bool Equals(object obj) { bool isEqual = false; if (obj != null && this.GetType() == obj.GetType()) { var that = obj as Address; isEqual = this.Province == that.Province && this.City == that.City && this.County == that.County && this.Street == that.Street && this.Zip == that.Zip; } return IsEqual; } public override int GetHashCode() { return this.ToString().GetHashCode(); } public override string ToString() { string address = $"{this.Province}{this.City}" + $"{this.County}{this.Street}({this.Zip})"; return address; } } ``` - 作用 - 符合通用语言,更简单明了的表达简单业务概念 - 简化设计,减少不必要的数据库表设计 - 值对象不会孤立存在,可作为所属实体的数据列 - 多个值对象序可以劣化到单个列