DDD - 使聚合根再水化?

DDD - Rehydrate aggregate roots?

我所有的实体都是接口的实现。他们的大部分属性都是只读的。
我的存储库包含对我拥有所有接口的库项目的引用,因此从技术上讲,存储库可以 保存 聚合根,而无需了解它的实际实现(我相信成为 +1).
这里的问题是:如果大多数属性是只读的,我如何在不违反 OOP 原则的情况下重新水合聚合根?存储库是否应该包含对域项目的引用并了解接口的具体实现?

should the repository hold a reference to the domain project and be aware of the concrete implementation of interfaces?

正如埃文斯在蓝皮书中所描述的那样; Repository 是实现所扮演的角色,以防止应用程序直接改变底层数据。同样,聚合根是一个角色——我们不让应用程序接触实际实体,而只是它的有限部分。

存储库的实现是模型的一部分,因此它可以更多地了解所表示的特定实体;包括知道如何从它们中提取可以传递给持久性组件进行存储的状态表示。

要选择特定上下文,假设我们正在对 TradeBook 建模,其中一个有趣的用例是客户下订单。 在 Java 中,Repository 接口的实现 -- 应用程序知道的位,可能看起来像

interface API.TradeBookRepository<TradeBook extends API.TradeBook> {
    TradeBook getById(...);
    void save(TradeBook);
}

interface API.TradeBook {
    void placeOrder(...);
}

所以应用程序知道它可以访问存储库,但它对实现一无所知,只知道它的承诺 将提供支持 placeOrder 的东西

因此应用程序代码如下所示:

API.TradeBookRepository<? extends API.TradeBook> repo = ....

API.TradeBook book = repo.getById(...);
book.placeOrder(...)
repo.save(book)

但是给定的存储库实现通常与本书的特定实现相关联;他们配对在一起。

class LIFO.TradeBook implements API.TradeBook {
    ...
}

class LIFO.TradeBookRepository implements API.TradeBookRepository<LIFO.TradeBook> {
    ...
}

how can I rehydrate a aggregate root without breaking OOP principles?

在某种程度上,你不能。好消息是,at the boundaries, applications are not object oriented.

您放入耐用商店的东西不是聚合根;它是某种状态的代表。我倾向于将其视为 Memento。您真正拥有的是两个函数 - 一个将特定聚合根实现(例如:LIFO.TradeBook)转换为 Memento,另一个将 Memento 转换为聚合根。

要点:与迁移数据库相比,您可能希望更频繁地更改域模型很多。因此,Memento 需要设计得稳定——实际上,Memento 是从旧域模型发送到新域模型的消息,因此许多 lessons of message verioning 适用。

简而言之,您的应用程序中的某个地方必须了解具体实现。如果你真的想保护存储库实现(而不是合约)不了解具体实体,那么这个责任就必须落在另一个合作者身上(例如,存储库会将再水化委托给抽象工厂)。

但是,对于聚合有单独的合同是非常罕见的,因为您通常只有这些业务概念的单一实现,并且通常没有您想要在单元测试中模拟它们的场景。因此,存储合约和实现大部分时间都是根据具体聚合定义的。