知识卡片

操作类型分离、角色契约分离与面向切面分离

结构图卡

内容

不同操作类型的代码分离——DDD的一个最佳实践是把查询和命令语句分离(CQRS):一是明确区分读写操作能避免误操作、让代码意图更清晰;二是查询和修改语句的执行频率、资源需求往往差别很大,分离后能让二者相互独立、互不影响,提升系统稳定性;这个思路还能进一步扩展到消息模式的细分(请求/响应、即发即忘、发布/订阅)。角色不同的代码分离——把消费者和生产者、客户端和服务端、接口与实现分开,双方只通过契约(接口)关联,只要遵守契约任何一方都能自主决策;这带来三个好处:可扩展性(新增消费者/客户端/接口无须改动其他部分)、跨平台支持(不同团队可选择适合自己的技术栈)、易于测试(每个角色职责和依赖契约明确,可以针对单个角色写独立测试、用模拟对象替代其他组件)。面向切面的关注点分离——面向对象方式处理日志记录、认证授权、监控、错误处理这类每个类都可能需要的通用技术需求时,必须在每个相关类里重复添加代码,造成冗余且难以维护;面向切面把这些横切关注点抽象成独立模块、与原始代码分离,只在运行时动态引入到目标对象中;服务网格的边车模式(Side Car)把这个思路进一步推进——关注点代码被部署为单独的进程或容器、与业务逻辑代码处于不同的执行环境,比传统AOP(仍在同一进程内)获得更大的灵活性和可扩展性。可迁移启发:遇到”同一段逻辑(日志、鉴权、监控)在很多个类里反复出现”这种代码坏味道时,先判断这段逻辑是不是真正意义上的横切关注点——如果是,直接考虑AOP或者边车模式去统一抽离,而不是满足于”抽成一个公共方法到处调用”这种表面上的复用,因为后者仍然要求每个调用方显式引入这段逻辑,没有真正做到”运行时动态引入、业务代码零感知”。

结构图

flowchart TB
  Q["操作类型分离(CQRS)<br/>查询/命令分离,可再细分消息模式"]
  R["角色分离(消费者/生产者,客户端/服务端)<br/>通过契约关联"]
  R --> R1["可扩展性/跨平台支持/易于测试"]
  A["面向切面分离(日志/鉴权/监控等横切关注点)"]
  A --> A1["传统AOP:同一进程内动态引入"]
  A --> A2["边车模式(Side Car):独立进程/容器,更大灵活性"]

参考来源

- 位置:《架构师启示录:知识模型、落地方法与思维模式》第8章《系统实现》之"8.1.2 代码中的分离性"第5、6、7条(源文件:_epub-src/EPUB/xhtml/chapter12.xhtml) - 结论依据:原文说明"在DDD中,有一个最佳实践是将查询和命令语句分离……将不同角色的代码进行分离也是一种常见的做法……它们之间只是通过契约(或接口)进行关联……面向切面通过将这些横切关注点抽象成独立模块,并与原始代码分离,只在运行时动态地将其引入目标对象中……在边车模式下,关注点代码被部署为一个单独的进程或容器", 直接支撑本卡关于操作类型/角色/切面三种分离思路的结构图。 - 原始内容:如果使用传统的面向对象方式处理这些需求,就必须在每个相关类中重复添加相应的代码,这就导致代码冗余且后续难以维护。