【问题标题】:DDD Factory ResponsibilityDDD 工厂责任
【发布时间】:2016-03-07 18:19:59
【问题描述】:

如果有以下代码。

public class CountryFactory : IEntityFactory
{
    private readonly IRepository<Country> countryRepository;

    public CountryFactory(IRepository<Country> countryRepository)
    {
        this.countryRepository = countryRepository;
    }

    public Country CreateCountry(string name)
    {
        if (countryRepository.FindAll().Any(c => c.Name == name))
        {
            throw new ArgumentException("There is already a country with that name!");
        }

        return new Country(name);
    }
}

从 DDD 方法来看,是创建Country 的正确方法。或者最好有一个CountryService 来检查一个国家是否存在,如果不存在,只需调用工厂返回一个新实体。这意味着服务将负责持久化实体而不是工厂。

我对责任应该放在哪里有点困惑。特别是如果需要创建更复杂的实体,而不是创建一个国家那么简单。

【问题讨论】:

  • 我认为问题可能来自您使用的词汇。该 create 方法实际上是一个具有默认值的查找,如果它不存在...它不是真正的 create...因此我发现很难认为它是无处不在的语言的一部分。如果不知道该实体是如何使用以及与之相关的,我发现很难说其他任何事情,因为有时逻辑可能位于域服务、应用程序服务、工厂、存储库或只是一个 新实例 视情况而定。
  • 好吧,我真的需要知道将回购注入工厂是否有效/良好的做法。并且是否所有实体都有创建它们的工厂。它真的归结为,我是根据持久化的内容创建实体,还是创建实体,尝试持久化它并担心它是否会出错。

标签: domain-driven-design factory-pattern ddd-repositories


【解决方案1】:

在 DDD 中,工厂用于封装复杂对象和聚合创建。通常,工厂不是作为单独的类实现的,而是作为返回新聚合的聚合根类上的静态方法。

工厂方法比构造函数更适合,因为您可能需要技术构造函数来进行序列化,而var x = new Country(name) 在您的通用语言中几乎没有意义。这是什么意思?为什么在创建国家时需要名称?你真的创建了国家,新国家出现的频率,你甚至需要为这个过程建模吗?如果您开始考虑除了战术模式之外的模型和无处不在的语言,那么所有这些问题都会出现。

工厂必须返回有效对象(即聚合),检查其中的所有不变量,但不检查外部。工厂可能会接收服务和存储库作为参数,但这也不是很常见。通常,您有一个应用程序服务或命令处理程序,它会执行一些验证,然后使用工厂方法创建一个新的聚合并将其添加到存储库中。

Lev Gorodinski 也有一个很好的答案Factory Pattern where should this live in DDD?

此外,Red Book 的第 11 章详细描述了工厂的实现。

【讨论】:

    【解决方案2】:

    将存储库注入工厂是可以的,但这不应该是您首先关心的问题。起点应该是:您的业务领域需要什么样的一致性?

    通过检查CountryFactory 中的国家/地区名称唯一性,这是您的域层的一部分,您给自己的印象是国家/地区将始终保持一致。但是唯一的聚合是Country,并且由于没有AllCountries 聚合作为一致性边界,因此不能保证尊重这个不变量。有人总是可以在您检查之后潜入一个与添加的国家名称完全相同的新国家/地区。您可以做的是将 CreateCountry 操作包装到一个事务中,该事务将锁定整个国家集(如果您使用 RDBMS,则锁定整个表),但这会损害并发性。

    还有其他选择。

    • 为什么不利用数据库唯一约束来强制国家名称不变?作为补充,您还可以在 UI 级别设置另一个检查点,以警告用户他们输入的国家/地区名称已被占用。这将需要另一个“查询”服务,它只调用CountryRepository.GetByName(),但返回的国家/地区预计不会被修改。

      很快您就会意识到实际上有两种模型 - 一种可以在给定的时间为您提供一些域数据,以便您可以将其显示在用户界面上,另一种公开操作(AddCountry ) 并且将保证域不变量始终成立。这是迈向 CQRS 的第一步。

    • 添加或修改国家/地区的频率是多少?如果它那么高,我们真的需要一个国家名称在任何时候都是唯一的吗?如果我们放宽限制,允许用户临时创建一个重复的 Country name ,岂不是解决了很多问题?一种机制可以稍后检测到重复项并采取补偿措施,暂停新添加的国家/地区并联系用户要求他们更改名称。 A.k.a 最终一致性而不是立即一致性。

    • Country 需要是一个聚合吗?如果它是一个值对象并在每个使用它的实体中重复,成本会是多少?

    【讨论】:

    • @Shane Van Wyk 你最终弄清楚了吗?我得到了 guillaume31 关于域实体不变量的观点,但是当需要唯一约束并且无法使其成为值对象时,应该如何处理它?
    猜你喜欢
    • 2012-02-28
    • 1970-01-01
    • 1970-01-01
    • 2012-07-08
    • 1970-01-01
    • 2019-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多