2016-03-04 76 views
0

如果有以下代码。DDD工厂责任

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的正确方法。或者是否有更好的办法来检查一个国家是否存在,如果不存在,只需致电工厂返回一个新的实体。这意味着该服务将负责坚持实体而不是工厂。

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

+1

我认为这个问题可能来自您使用的词汇。 * create *方法实际上是一个具有默认值的查找,如果它不存在的话...它不是真正的*创建* ...因此我觉得很难认为它是无处不在的语言的一部分。如果不知道该实体是如何使用以及与什么相关的,我发现很难说其他任何东西,因为有时逻辑可能位于域服务,应用程序服务,工厂,存储库或只是一个*新实例*,具体取决于情况。 – Augusto

+1

嗯,我真的需要知道将回购注入工厂是否有效/良好实践。所有的实体是否都有制造它们的工厂?它真的下降了,我是否创建了一个基于持久化的实体,或创建实体,试着坚持它,并担心它是否出现错误。 –

回答

1

注入库到厂是好的,但它不应该是你的第一个问题。起点应该是:您的业务领域需要什么样的一致性?

通过检查CountryFactory国家名称的单一性,是您的域层的一部分,你给自己的印象是,国家将始终是一致的。但唯一的总和是Country,并且因为没有AllCountries聚合体充当一致性边界,所以不能保证对这个不变性的尊重。有人可以随时潜入一个新的国家,这个国家的名称与刚刚添加的国家完全相同,只是在您检查完毕后。你可以做的是包裹CreateCountry操作成(如果你使用RDBMS,从而使整个表),这将锁定整组的国家,但这会伤害并发事务。

还有其他选择需要考虑。

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

    很快你会意识到有两种模式 - 一种可以在特定时刻为您提供一些域数据,以便您可以在用户界面上显示它,另一种可以显示操作( AddCountry),并保证域不变量始终保持不变。这是迈向CQRS的第一步。

  • 正在添加或修改国家的频率是多少?如果真的很高,我们是否真的需要一个国家名称在任何时候都是独一无二的?如果我们放宽了限制并允许用户临时创建重复的国家名称,它不会解决很多问题吗?一种机制可以在稍后检测到重复项并采取补偿措施,将新增加的国家暂时搁置并向用户伸出手,要求他们更改名称。 A.k.a最终一致性而不是直接一致性。

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

+0

@Shane Van Wyk你有没有想到最终?我对Guillaume31的关于域实体不变的观点有所了解,但是当需要唯一的约束并且没有办法使它成为Value Object时,它应该如何处理呢? – Sergio

1

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

工厂方法比构造函数更适合,因为您可能需要具有用于序列化目的的技术构造函数,并且var x = new Country(name)在无处不在的语言中的含义很少。这是什么意思?为什么创建一个国家时需要一个名字?您是否真的创建了国家,新国家出现的频率如何,您是否甚至需要对此流程进行建模?如果你开始考虑你的模型和无处不在的语言,除了战术模式之外,所有这些问题都会出现。

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

还有由利Gorodinski这里Factory Pattern where should this live in DDD?

一个很好的答案此外,实施工厂在Red Book的第11章详尽地描述。