故事:咖啡店的领域驱动之旅
1. 实体(Entity)——独一无二的顾客
在“豆香咖啡店”,每位顾客进店时都会获得一个专属会员卡号(唯一标识符)。无论顾客是买一杯美式还是换了新发型,只要出示这个卡号,店员就能准确识别他。
- 为什么重要:就像实体必须通过ID标识,会员卡号确保顾客的唯一性。即使两位顾客同名同姓,系统也能通过卡号区分他们。
2. 聚合与聚合根(Aggregate & Aggregate Root)——订单的核心
小美点了一杯拿铁和一个蛋糕,店员将这整个订单视为一个聚合:
- 订单(聚合根):包含拿铁(实体)、蛋糕(实体)、总价(值对象)。
- 规则:所有操作必须通过聚合根(订单)进行。例如,小美想加一份饼干,必须修改订单(聚合根),而不是直接操作拿铁或蛋糕。
- 作用:确保订单状态一致(比如总价自动更新)。
3. 值对象(Value Object)——咖啡的价格标签
店员在订单上写下“拿铁:¥30”。这里的“¥30”是一个值对象:
- 不可变:一旦写下,价格不能直接涂改。若小美换大杯,需划掉旧价格,重新写“¥35”。
- 带上下文:“¥30”不仅是数字,还隐含了货币单位和商品关联。
- 验证:店员会检查价格是否合理(如负数无效)。
4. 领域事件(Domain Event)——后厨的铃声
订单完成后,店员按下“制作完成”按钮,触发领域事件:
- 事件内容:“订单123的拿铁和蛋糕已备好,请送至2号桌”。
- 结果:后厨听到铃声开始制作,清洁组收到事件后准备清理桌面。
- 价值:解耦订单处理与后续操作,避免店员挨个通知每个部门。
5. 领域服务(Domain Service)——计算折扣的智能助手
小美是VIP顾客,店员需要计算她的折扣:
- 输入:订单总价¥65 + VIP等级。
- 处理:调用“折扣计算器”(领域服务),结合促销规则和用户等级,得出最终价格¥58。
- 特点:折扣规则独立于订单和用户,可灵活调整。
6. 应用服务(Application Service)——店长的指挥台
店长负责协调整个流程:
- 接收请求:小美下单。
- 调用领域逻辑:验证订单、计算价格、触发制作事件。
- 管理外部操作:连接收银台(支付)、库存系统(扣减原料)。
- 关键点:店长不参与具体业务规则(如如何做咖啡),只确保流程正确执行。
故事的总结
- 实体如顾客:靠唯一ID识别,即使属性变化,身份不变。
- 聚合如订单:核心对象管理一组关联操作,确保一致性。
- 值对象如价格:描述属性,不可变且自带验证。
- 领域事件如铃声:异步通知其他部门,提升效率。
- 领域服务如折扣计算:处理跨多个对象的复杂逻辑。
- 应用服务如店长:协调全局,但不插手具体业务规则。
通过咖啡店的日常运营,领域驱动设计的核心思想变得触手可及——将复杂业务分解为高内聚的模块,通过明确边界和协作规则,让系统像一家高效运转的咖啡店一样稳定可靠。