每当我看Axon Bank时我开始想知道是否应该遵循一组事件和命令的设计规则。
在 Axon Bank 中,事件和命令都完全由原语组成。在我的应用程序中,我倾向于尽可能避免原始使用,主要是为了构建一个表达域并在任何可以获得的地方都具有类型安全性。
Axon 本身附带了一些 DDD 引用,但无论我浏览哪些文档,都没有一个示例使用复合对象作为事件/命令有效负载的一部分。
这让我很困惑。对成熟的 xml 和 json 序列化的内置支持不仅仅是拥有一些键值对。
我知道事件往往是小而简单的结构,因为它们只反射(reflect)增量状态变化,但复杂的域模型和事件(条目)之间总会存在某种差距。
<小时/>在我的域中,我可以有一堆类,例如 OverdraftLimit
、CurrentBalance
、Deposit
和 AccountIdentifier
。
现在有两种可能的方法来设计事件和命令:
1。基元和扩展转换
- 将事件视为带有漂亮标签的原始数据
- 原始数据“进入”应用程序后立即将其转换为强大的对象
创建事件时,只需再次将其剥离即可。
public class BankAccountcreatedEvent { private final String accountIdentifier; private final int overdraftLimt; // ... }
还有其他地方:
public void on (BankAccountCreatedEvent event) { this.accountIdentifier = AccountIentifier.fromString(event.getAccountIdentifier()); this.overdraftLimit = new OverdraftLimit(event.getOverdraftLimit()); }
优点:
- 简单的命令/事件 API,没有任何奇怪的依赖项
- 让分发变得更容易
- 仅当实际事件结构发生变化时才需要升级者,因此可以轻松预测。
缺点:
- 需要编写和维护巨大的转换层
- 主要出于技术原因将事件/命令与域模型的其余部分解耦,引入了新的、人为的上下文间隙
2。富有表现力的有效负载
直接使用复杂类型作为属性
public class BankAccountCreatedEvent { private final BankAccountIdentifier bankAccountIdentifier; private final OverdraftLimit overdraftLimit; //.. }
优点:
- 编写更少,更容易阅读
- 将自然所属的东西放在一起
缺点:
- 领域逻辑会间接影响事件结构,因此需要更频繁地进行向上转型,并且难以预测。
我需要第二意见。有推荐的方法吗?
最佳答案
首先要记住的是, Activity 的序列化形式是您的正式契约(Contract)。最终如何在 Java 类中表示这一点取决于每个应用程序。例如,如果您将序列化程序配置为忽略未知字段,则可以保留您不关心的字段。
就我个人而言,我不介意事件中的原语。但是,我确实理解对某些字段使用显式值对象的值(value),因为它们允许您表达每个字段涉及的“数学”。就标识符而言,它们可以防止“混淆”,即使用标识符意外地尝试识别另一种类型的对象。
最终,这并不重要。通过一些简单的 Jackson 注释,您可以将这些值对象转换为 JSON 中的简单值。查看@JsonValue ,例如。
public class BankAccountCreatedEvent {
private final BankAccountIdentifier bankAccountIdentifier;
private final OverdraftLimit overdraftLimit;
//..
}
将映射到:
{
"bankAccountIdentifier": "abcdef1234",
"overdraftLimit" : 1000
}
如果 BankAccountIdentifier 和 OverdraftLimit 类都具有 @JsonValue 注释方法,该方法将返回其“简单”值。
关于java - 处理 Axon 中的重要命令和事件负载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44267258/