展开
拓展 关闭
订阅号推广码
GitHub
视频
公告栏 关闭

领域驱动设计简介

单一职责原则

点击查看详情
  • 两顶帽子: 为了实现新的功能,我们在原有代码的基础上,在不添加新功能的前提下调整原有程序结构,我们抽取出了 Strategy 这样一个接口和“不折扣”这个实现类;这时,原有程序变了吗?没有。但是程序结构却变了,增加了这样一个接口,称之为“可扩展点”。在这个可扩展点的基础上再实现各种折扣,既能满足“开放-封闭原则”来保证程序质量,又能够满足新的需求。当日后发生新的变更时,什么类型的折扣有变化就修改哪个实现类,添加新的折扣类型就增加新的实现类,维护成本得到降低

  • 例如我们的初始需求如下

  • 第一次需求变更为商品则扣

  • 因为需要在付款这个方法中实现折扣,那么就需要分析付款折扣的关系,付款发生改变时,折扣是否会发生改变,折扣发生改变时,付款是否会发生改变;简单理解就是,调用付款这个方法,给蔬菜付款或者给水果付款,它们的折扣是否会发生改变,答案是不会(付款的金额变化,折扣还是原来的则扣逻辑;折扣变化,需要进行折扣的付款金额还是原来的金额),折扣不会随着付款的改变而改变,付款也同样会发生改变;通过分析,付款和折扣是两个不同的事件,那么就不能写在同一个方法中,或者说不能写在同一个类中

  • 另外在折扣中又分为限时折扣、限量折扣等,同过分析限时折扣与付款的关系,分析限量折扣与付款的关系;可以写一个接口编写不同的折扣方法,在实现类中实现折扣方法

  • 同样第二次需求变更增加会员

  • 第三次变更增加支付

数据库设计

点击查看详情
  • 关系型数据库

  • 在面向对象的开发中:根据需求文档,进行用例设计,根据用例设计领域模型,以领域模型作为核心进行数据库设计和程序设计

  • 一对一的关系:一个过错行为对应一个申辩申请单,可将过错行为表的主键作为申辩申请单的外键,并将该字段升级为该表的主键

  • 多对一的关系:平时我们查询通常是join关联查询,不过这么做查询性能差,解决方案是:先查询过错行为表,再根据外键查询关联的表

  • 一对多的关系

  • 多对多的关系

  • 继承方案一:将所有字段写在一张表

  • 继承方案二:将相同的字段提取出来,不同的字段作为一张表,不同字段的表的主键作为相同字段的表的外键

  • 继承方案三:将相同字段的表作为父类,不同字段的表作为子类

点击查看详情
  • 非关系型数据库

  • 将需要连接查询的数据在写入数据库前先进行join操作,查询的时候直接查询即可

领域模型

点击查看详情
  • 服务

  • 实体:例如某个实体类,它的属性可能随着时间不断变化,例如用户实体类:属性可以是name,也可以是username

  • 值对象:例如真实世界中不会改变的地名等

  • 区分:值对象,例如圆形是一种形状,红色是一种颜色,形状和颜色就是值对象,不会改变

  • 贫血模型

  • 充血模型

聚合

点击查看详情
  • 聚合体现的是整体与部分的关系,当整体不存在时,部分也就没有意义了

  • 如何判断是否是聚合关系,例如饭店和菜单,账单和账单明细,当饭店不存在时,菜单也就没有意义了,账单不存在时,账单明细也就没有意义了,这种依存关系就是聚合

  • 饭店和菜单也可以设计成不是聚合关系,当饭店删除时,菜单依然存在,

  • 整体则作为聚合根,是外部访问部分的唯一入口;当聚合内部发生改变时,与聚合外部无关

  • 账单与账单明细的聚合案例

  • 在只有crud是适合采用聚合,而在统计汇总时则直接使用sql查询即可

  • 聚合的设计实现,通过仓库来实现对数据库的访问

  • 在工厂中装配仓库所需的对象,之后返回给仓库

界限上下文

点击查看详情
  • 问题子域

  • 限界上下文

事件风暴

点击查看详情
  • 参考
  • 事件风暴会议:提前邀请Project的所有相关人(包括开发,测试,产品,业务分析,UI/UX等),一起讨论
  • 事件Event:已经发生的事实,如用户已注册,用户已登录,用户已发送等
  • 决策命令Command:产生这个事实的的动作,如注册用户、登录用户、发送信息
  • 发起命令的参与者User/Actor:如用户1在注册账号,用户2在登陆账号
  • 读模型Read Model:某个Actor做出决策命令Command的前提是需要看到某些信息,如发送信息时需要看到对方的信息
  • 聚合Aggregate:某个Actor在某个聚合调用某种Command产生了某个Event,也就是整个流程结束
  • 外部系统External System和规则Policy:Event不一定由前面所说的某个Actor触发Command而产生,也可能是由外部系统或者某种规则自动触发Command而产生

  • 例如用户选餐是否是一个领域事件,答案是,因为用户选餐只是一个查询操作,并没有数据保存到数据库中;在ddd中查询操作则采用其他方式

微服务拆分

点击查看详情
  • 微服务间高内聚低耦合:例如用户下单的微服务要查询用户信息,并不是直接查询,而是调用用户注册这个微服务的接口,同样也不是直接调用,而是去注册中心调用名称叫用户注册的微服务的接口

  • 主题域和拆分域:在用户下单这个问题域中,用户信息来源于用户注册这个限界上下文,菜单信息来源于饭店管理这个限界上下文,那么用户下单作为主题域,用户注册饭店管理作为支撑域

  • 同样在饭店接单这个问题域中,用户信息来源于用户注册上下文,订单信息来源于用户下单上下文

  • 用户下单上下文中下单成功后,饭店接单上下文如何知道用户下单了呢,需要通过消息队列将用户下单的消息发送给饭店接单上下文

  • 数据库设计参考

  • 落实到微服务设计 -> 落实到数据库设计 -> 落实到贫血模型与充血模型的设计

  • 如何跟踪订单状态,同样是使用消息队列的方式,将消息传递给下一个微服务

  • 例如多个团队开发微服务,其他团队要求你提供接口时,应该怎么做

  • 当其他团队要求你变更接口,为了不影响其他业务,应该在要变更接口的基础上修改,若实在要新增一个接口才去新增

  • 防腐层:一个上下文通过一些适配和转换与另一个上下文交互

  • 例如feigen接口就是防腐层

  • NewSQL:就是在传统关系型数据库上集成了 noSQL 强大的可扩展性

  • 数据库选择

整洁架构

点击查看详情
  • 技术中台

  • 例如在以往的架构中我们使用hibernate2进行开发,后来我们又需要用hibernate3进行升级,但是hibernate2与业务代码高度耦合,这时重构系统就非常麻烦,解决方案就是将hibernate2独立出来,并为它写一个实现类,我们使用实现类的方法即可,之后进行系统升级的时候,只需为hibernate3写一个实现类;这样的重构方式就能将影响降到最低

  • 核心:将底层架构与业务代码解耦

  • 主动适配器又称北向适配器,用户通过浏览器等不同方式发送请求,通过北向适配器调用应用层,被动适配器又称南向适配器,即业务领域层完成业务处理后,将数据持久化到数据库

中台

点击查看详情
  • 什么是中台


  • 如何提升团队交付产品的速度:将产品拆分成一个个微服务,不同的团队开发不同的微服务,每个团队负责各自的微服务,从开发到部署和维护

  • 这个开发方式就是大前端+技术中台

  • 大前端

  • 这就需要团队中的每个成员都懂前端、后端、数据库、大数据等,但这样显然是不可能的;这个问题该怎么解决呢?那就由专门的底层架构团队来编写技术中台,其他开发团队则将更多的精力投入到业务中去

  • 技术中台搭建

  • 简易技术中台

实现技术中台

点击查看详情
  • 所有增删改操作采用领域驱动设计,查询操作直接采用sql语句;中台设计为单dao和单controller

  • 单controller使用OrmController,设计流程如下:

  • 单dao设计使用xml配置,不建议使用注解


  • 查询功能设计

  • 传统ddd架构:展现层即前端ui,应用层即MVC层,领域层即service



  • 通用仓库与通用工厂的设计

ddd案例

点击查看详情
  • 用户故事是理解业务,使能故事是一个好的技术中台

  • 案例

  • 事件溯源

  • 例如我们要实现用户下单的需求,只需要理清楚用户下单要处理的业务,至于下单完成后要做的事情不需要管了

  • 领域事件的设计实现

  • 总结

posted @ 2022-01-01 11:29  DogLeftover  阅读(20)  评论(0编辑  收藏  举报