【问题标题】:Java: How to marry JPA and high-level business rules? (Bounded contexts)Java:如何结合 JPA 和高级业务规则? (有界上下文)
【发布时间】:2012-12-26 17:54:24
【问题描述】:

问题上下文

所以我将我的应用程序组织到有界上下文中(Eric Evans 的“领域驱动设计”)。有界上下文之一是“游戏性上下文”。例如,它包含一个接口Gamer

public interface Gamer {
    void setFriends(Set<Gamer> friends);
    Set<Gamer> getFriends();
    ....
}

还有一个实现可以将Gamer 的状态持久化到数据库中。

@Entity
public class JpaGamer implements Gamer {
    private String someData;
    private String someSensitiveData;

    public setFriends (Set<Gamer> friends) {
        ...
    }

    ...
}

很远很远,在另一个称为“帐户上下文”的有界上下文中,我有处理我的应用程序用户的类和接口。例如,有一个名为Account 的接口。

public interface Account{
    boolean isSignedUp();
    ....
}

所以用户 /Account 可以注册或不注册。对于任何Account,都有一个对应的Gamer

挑战

我有一个业务规则:永远不要保留与未注册相关的敏感数据Account

例如,这意味着某些未注册的AccountJpaGamer 实例无法将数据写入someSensitiveData 字段。您可以非正式地说这个JpaGamer 是“未注册的JpaGamer”。

我不想将任何与帐户相关的逻辑硬编码到任何与游戏相关的内容中(反之亦然)。

我怎样才能在 Java 中实现这样的业务规则,而不用来自另一个有界上下文的概念污染任何一个有界上下文?

为了满足业务规则,我的想法是,只要有“未注册的JpaGamer”,我就将JpaGamer 包装在SparsePersistingGamer 中。 SparsePersistingJpaGamer 根本不会将任何可能篡改someSensitiveData 的方法转发给底层JpaGamer
但是现在我遇到了someGamer.getFriends() 方法的问题。对于SparsePersistingGamer,它会懒惰地从JPA 加载所有玩家的朋友,返回一组不知道(和任何其他)业务规则的普通JpaGamers,因此坚持someSensitiveData 可能“非-注册JpaGamers"。

您采用哪些策略来处理类似和相关的情况?

【问题讨论】:

  • DDD nitpick:Gamer 真的应该直接访问 Set&lt;Gamer&gt; 的朋友,而不是 Set&lt;GamerId&gt; 的朋友吗?所有连接的Gamers 的整个友谊网络听起来太大而不能成为单个聚合根。

标签: jpa domain-driven-design business-rules bounded-contexts


【解决方案1】:

绝不保留与未注册用户相关的敏感数据 帐户。

此规则表明Gamer 实体需要了解其帐户状态。我不熟悉您的域,因此我无法评论边界,但让我们假设确实有两个不同的 BC:游戏玩家和帐户。这表明需要某种同步 - 来自 Accounts BC 的信息需要到达 Gamers BC。信息可以通过多种方式传递。

一种方法是使用事件驱动架构 (EDA) 对每个 Gamer 实体中的帐户状态进行非规范化处理。这不会污染 Gamers BC,因为帐户状态是影响实体行为的适当信息。可以设置 EDA,以便 Account BC 发布有关状态更改的事件,并且 Gamers BC 订阅这些更改并更新 Gamers 实体中的非规范化数据。这里的优点是两个 BC 将是自治的。但是要考虑的一个因素是eventual consistency - Account BC 中的更改不会与 Gamers BC 在事务上保持一致。这通常是可以接受的,因为延迟可能会越来越小。

另一种方法是将帐户状态数据提供给 Gamers 实体上使用该信息的所有行为。此信息将由实现与玩家实体相关的用例的应用程序服务检索。 GamerApplicationSerivce 会呼叫 Accounts BC。这种方法的优点是简单——无需设置事件处理。缺点是自主性降低 - Accounts BC 必须可用于需要帐户状态信息的 Gamer 用例。

另外,我建议您避免使用不同的实体实现,从而避免使用实体接口。这增加了不必要的复杂性,并使推理行为变得更加困难。相反,在实体中明确表达所有领域逻辑,并通过环境应用程序服务或通过事件驱动的非规范化提供所需的数据。

【讨论】:

  • 将事件驱动架构应用于我的问题似乎很有希望!谢谢你的建议!我将研究其影响。
  • 查看更新 - 添加的不是 EDA 中的最终一致性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 2012-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-17
相关资源
最近更新 更多