DDD DCI和领域事件(领域驱动设计)


xinwang_m@163.com
2020-07-20 04:43:18 (4年前)
DDD;DCI

DDD是领域驱动设计(Domain-Driven Design )的简称,DDD是一种分析设计建模方法,它倡导统一语言,提出了实体和值对象 以及聚合根等概念,借助DDD我们能够在结构理清需求中领域模型。DDD专题。

DDD是领域驱动设计(Domain-Driven Design )的简称,DDD是一种分析设计建模方法,它倡导统一语言,提出了实体和值对象 以及聚合根等概念,借助DDD我们能够在结构理清需求中领域模型。DDD专题。

  1. DCI: Data数据模型, Context上下文或场景, Interactions交互行为是一种新的编程范式,由MVC发明人Trygve Reenskaug提出。 DCI架构是什么?

![](/user/files/4CQpDR_56iqJ2AMLM_hn8x2i1_BZcmtir0iK7oRlE9A.png)

  1. DCI的关键是:
  2. 1. 要让核心模型非常瘦.
  3. 2. 逻辑或行为应该放在角色这个类中
  4. Event Sourcing是由Martin Fowler提出,是将业务领域精髓(尤其是最复杂的)与技术平台的复杂性实现脱钩的天作之合。为什么要用Event Sourcing?或 Domain Events 救世主
  5. 下面我们将演示如何将上述三者在实践中结合在一起?
  6. 以机器人Robot这个需求为案例,下图是Robot描述,我们根据这种图通过DDD建模。
  7. 从上面这张图中,我们根据DDD的实体聚合根等定义,得出如下类图:
  8. 可见,Robot作为一个聚合集合的根实体,它有四个重要部分组成,这些组成部分与Robot形成一种高凝聚的组合关系。缺一不可。
  9. 有了这样的结构关系,我们还将细化方法行为,根据 对象的责任与职责,也就是职责驱动开发方法论,它提出一种角色职责的模型:roles-and-responsibilities ,见Object Design: Roles, Responsibilities, and Collaborations),什么是职责呢?职责就是那些knowing what; doing what; deciding what.
  10. 那么Robot如果作为一个智能机器人,它应该有哪些职责呢?
  11. Robot的职责功能是能听,能看或能感觉,听 感觉这些都是其作为一个智能机器人角色的职责。
  12. 那么,下一步关键是,如何实现这些职责呢?是否是将这些职责设计作为Robot实体类的方法呢?如下:

![](/user/files/BFvmh_MzyCGDyluUS0_xKISpIEGrG2VXAGF7GkKerI4.png)

  1. 这样设计以后,可能会导致Robot实体类非常臃肿,是一个庞大的对象,这有违背DCI要旨。
  2. DCI认为要保持模型的精简,听 感觉这些行为是Robot作为一个智能机器人,不是普通机器人,这样一个特殊角色具备的职责,应此,应该将这些行为放入一个叫智能机器人的角色中。当在运行时需要的场景context时,我们将这个角色中的职责行为注入到精简的数据模型中,如下图:

![](/user/files/W_ccxGQ14YytCjsP6rNYTptGAQtFdQn39PGk7Sy2q2k.png)

  1. 这样的例子很多,一个人在家是父亲,在单位是经理,父亲和经理都是角色,是不是要将这些角色行为比如签字 烧菜这些和具体业务场景有关的职责放入“人”这个类中呢?显然不是。
  2. 又比如银行账户Account有三种角色:两个是设计角色 BankAccount银行账户 FinancialAsset理财账户, 另外一个角色是技术角色,它又是EJB的实体Bean专门用来实现持久化保存。

![](/user/files/BYotn4GaKJlG_zUGXTuGCzMivZsl27kh4sojgHTzeCc.png)

  1. 那么如何将上面DCI设计或职责驱动落实为代码呢?特别是Robot实体类和角色智能机器人的行为如何在运行时场景结合呢?这非常类似桥模式:

public String hello(String id) {
Robot robot = robotRepository.find(id);
//将角色智能机器人IntelligentRole的行为注入到Robot数据对象中
IntelligentRole intelligentRobot = (IntelligentRole) roleAssigner.assign(robot, new IntelligentRobot());
//得到一个混和robot将具有听 看 感觉等能力行为
return “Hello, ” + intelligentRobot.hear();
}
类似Account的实体持久化角色,, Robot也有一个保存自己到数据库的技术职责,Robot保存自己应该是首先由自己发出这样意愿,而不是被保存,是主动保存,其次保存数据库这个动作耗时,影响性能,因此,我们使用领域事件Domain Events来间接实现。

  1. 一个PublisherRole是保存事件发送者 Robot可以扮演这样一个角色发出保存事件。:

@Introduce(“message”)
public class PublisherRoleImp implements PublisherRole {

@Send(“saveme”)
public DomainMessage remember(Robot robot) {
return new DomainMessage(robot);
}
}

  1. 保存事件的接受方就是DDD中定义的仓储Respository:

@Component
@Introduce(“modelCache”)
public class RobotRepositoryInMEM implements RobotRepository {
…..

//保存事件的订阅者 真正实现数据库保存
@OnEvent(“saveme”)
public void save(Robot robot) {
memDB.put(robot.getId(), robot);
}

…..
}

  1. 那么 Robot在什么时候扮演事件发送者发出保存自己的命令呢?可以在任何时候,下面是一个context

public void save(Robot robot) {
PublisherRole publisher = (PublisherRole) roleAssigner.assign(robot, new PublisherRoleImp());
publisher.remember(robot);
}

  1. 至此,我们通过机器人Robot案例展示了DDD DCI和事件模型等分析设计实现的过程,当然复杂项目将比这个过程更加复杂,需要敏捷迭代,精炼出符合客观规律的核心模型。,DDD是领域驱动设计(Domain-Driven Design )的简称,DDD是一种分析设计建模方法,它倡导统一语言,提出了实体和值对象 以及聚合根等概念,借助DDD我们能够在结构理清需求中领域模型。DDD专题。

![](/user/files/_KsMScOCS_9a0BPdCUeutydbDM2mKbx4EEEMJTeNZ60.png)

  1. DCI: Data数据模型, Context上下文或场景, Interactions交互行为是一种新的编程范式,由MVC发明人Trygve Reenskaug提出。 DCI架构是什么?

![](/user/files/4CQpDR_56iqJ2AMLM_hn8x2i1_BZcmtir0iK7oRlE9A.png)

  1. DCI的关键是:
  2. 1. 要让核心模型非常瘦.
  3. 2. 逻辑或行为应该放在角色这个类中
  4. Event Sourcing是由Martin Fowler提出,是将业务领域精髓(尤其是最复杂的)与技术平台的复杂性实现脱钩的天作之合。为什么要用Event Sourcing?或 Domain Events 救世主
  5. 下面我们将演示如何将上述三者在实践中结合在一起?
  6. 以机器人Robot这个需求为案例,下图是Robot描述,我们根据这种图通过DDD建模。
  7. 从上面这张图中,我们根据DDD的实体聚合根等定义,得出如下类图:
  8. 可见,Robot作为一个聚合集合的根实体,它有四个重要部分组成,这些组成部分与Robot形成一种高凝聚的组合关系。缺一不可。
  9. 有了这样的结构关系,我们还将细化方法行为,根据 对象的责任与职责,也就是职责驱动开发方法论,它提出一种角色职责的模型:roles-and-responsibilities ,见Object Design: Roles, Responsibilities, and Collaborations),什么是职责呢?职责就是那些knowing what; doing what; deciding what.
  10. 那么Robot如果作为一个智能机器人,它应该有哪些职责呢?
  11. Robot的职责功能是能听,能看或能感觉,听 感觉这些都是其作为一个智能机器人角色的职责。
  12. 那么,下一步关键是,如何实现这些职责呢?是否是将这些职责设计作为Robot实体类的方法呢?如下:

![](/user/files/BFvmh_MzyCGDyluUS0_xKISpIEGrG2VXAGF7GkKerI4.png)

  1. 这样设计以后,可能会导致Robot实体类非常臃肿,是一个庞大的对象,这有违背DCI要旨。
  2. DCI认为要保持模型的精简,听 感觉这些行为是Robot作为一个智能机器人,不是普通机器人,这样一个特殊角色具备的职责,应此,应该将这些行为放入一个叫智能机器人的角色中。当在运行时需要的场景context时,我们将这个角色中的职责行为注入到精简的数据模型中,如下图:

![](/user/files/W_ccxGQ14YytCjsP6rNYTptGAQtFdQn39PGk7Sy2q2k.png)

  1. 这样的例子很多,一个人在家是父亲,在单位是经理,父亲和经理都是角色,是不是要将这些角色行为比如签字 烧菜这些和具体业务场景有关的职责放入“人”这个类中呢?显然不是。
  2. 又比如银行账户Account有三种角色:两个是设计角色 BankAccount银行账户 FinancialAsset理财账户, 另外一个角色是技术角色,它又是EJB的实体Bean专门用来实现持久化保存。

![](/user/files/BYotn4GaKJlG_zUGXTuGCzMivZsl27kh4sojgHTzeCc.png)

  1. 那么如何将上面DCI设计或职责驱动落实为代码呢?特别是Robot实体类和角色智能机器人的行为如何在运行时场景结合呢?这非常类似桥模式:

public String hello(String id) {
Robot robot = robotRepository.find(id);
//将角色智能机器人IntelligentRole的行为注入到Robot数据对象中
IntelligentRole intelligentRobot = (IntelligentRole) roleAssigner.assign(robot, new IntelligentRobot());
//得到一个混和robot将具有听 看 感觉等能力行为
return “Hello, ” + intelligentRobot.hear();
}
类似Account的实体持久化角色,, Robot也有一个保存自己到数据库的技术职责,Robot保存自己应该是首先由自己发出这样意愿,而不是被保存,是主动保存,其次保存数据库这个动作耗时,影响性能,因此,我们使用领域事件Domain Events来间接实现。

  1. 一个PublisherRole是保存事件发送者 Robot可以扮演这样一个角色发出保存事件。:

@Introduce(“message”)
public class PublisherRoleImp implements PublisherRole {

@Send(“saveme”)
public DomainMessage remember(Robot robot) {
return new DomainMessage(robot);
}
}

  1. 保存事件的接受方就是DDD中定义的仓储Respository:

@Component
@Introduce(“modelCache”)
public class RobotRepositoryInMEM implements RobotRepository {
…..

//保存事件的订阅者 真正实现数据库保存
@OnEvent(“saveme”)
public void save(Robot robot) {
memDB.put(robot.getId(), robot);
}

…..
}

  1. 那么 Robot在什么时候扮演事件发送者发出保存自己的命令呢?可以在任何时候,下面是一个context

public void save(Robot robot) {
PublisherRole publisher = (PublisherRole) roleAssigner.assign(robot, new PublisherRoleImp());
publisher.remember(robot);
}

  1. 至此,我们通过机器人Robot案例展示了DDD DCI和事件模型等分析设计实现的过程,当然复杂项目将比这个过程更加复杂,需要敏捷迭代,精炼出符合客观规律的核心模型。
0 条回复
  1. 动动手指,沙发就是你的了!
登录 后才能参与评论