32

我刚刚开始使用 DDD,所以也许这是一个愚蠢的问题......

实体可以访问存储库(通过某些 IRepository 接口)以在运行时获取值吗?例如,我想对属性强制执行“默认”选择:

class Person {
    private Company _employer;

    public Company Employer {
        get { return _employer; }
        set { 
            if(value != null) {
                _employer = value;
            } else {
                _employer = employerRepository.GetDefaultEmployer();
            }
        }
    }

    ...
}

我的问题是,做这样的事情是否严重违反了 DDD 原则。如果不是,我的下一个问题是提供存储库以供使用的最佳方式是什么?是否应该在创建 Person 对象时提供?

谢谢,P

4

5 回答 5

26

这不是严重违反 DDD,而是严重违反……嗯……这简直太可怕了(我说这个舌头在脸颊上):)。

首先,您的实体变得依赖于拥有一个存储库......这并不理想。理想情况下,您希望您的存储库创建 Person,然后为其分配在当前域上下文中有效所需的所有内容。

所以当你需要一个人时,你会去 personRepository.GetPersonWithDefaultEmployer() 并取回一个填充了默认雇主的人。personRepository 将依赖于一个employerRepository,并在返回它之前使用它来填充这个人。

PersonReposotory : IPersonRepository
{
    private readonly IEmployerRepository employerRepository;

    //use constructor injection to populate the EmployerRepository
    public PersonRepository(IEmployerRepository employerRepository)
    {
        this.employerRepository = employerRepository;
    }

    public person GetPersonWithDefaultEmployer(int personId)
    {
        Person person = GetPerson(personId);
        person.Employer = employerRepository.GetDefaultEmployer(personId);
        return person;
    }
}
于 2009-05-06T01:54:08.003 回答
7

您的问题的答案是标准:这取决于.

根据经验,永远不要这样做。保留您的实体而不引用存储库。

[戴上实用的帽子]在一些极其罕见的情况下,如果你有一个非常、非常、非常好的理由这样做,请添加一个大注释来解释你为什么这样做并这样做:添加参考或使用Double Dispatch通过存储库[脱帽]

此外,如果您希望遵循 DDD 原则,强烈建议您访问领域专家和迭代开发过程(请参阅Eric Evans - 我从本书中学到的知识 )。

与您的领域专家一起,您应该定义边界上下文,最重要的是聚合及其聚合根及其实体和值对象。走上 DDD 之路一开始并不容易,但回报是值得的。

关于您发布的代码的一些事情:

  1. 不建议在您的实体上设置公共设置器。使用能更好地表达意图的方法。

  2. 如果在未初始化 _employer 字段的情况下创建人员实例,则 Employer 属性的 getter 将返回 null。如果您随后将 Employer 属性的值设置为 null,则对 getter 的下一次调用将返回一个非 null 值。这可能出乎您班级的用户的意料。

  3. 设置 Person 的 Employer 的调用者(通过公共 setter 或公共方法)应该知道它想要设置的确切 Company 实例,即使它是默认实例。也许调用者可以拥有对存储库的引用。

  4. 根据您的具体领域,公司可能是一个价值对象。在这种情况下,您可以使用值对象的默认值来初始化它,而不是使用 null 来初始化 _employer。如果您只有很少的公司 (1-2) 并且它们是不可变的并且没有特定行为,则可能会出现这种情况。

于 2011-03-22T09:58:23.033 回答
5

我认为说一个实体不应该知道存储库很容易,但很难将其付诸实践。尤其是当聚合在其中获取大量 vo 集合时,我们必须对其进行重构并委托操作,例如添加到某些实际上充当存储库的域服务,以避免将整个集合加载到内存中的开销。
但我认为让实体知道存储库是不合理的。如果必须,则改用 域服务。我们还应该考虑存储库是否违反了单一责任原则——它应该被认为是聚合根的集合,而不是普通的工厂

于 2013-08-11T18:02:40.723 回答
0

首先,我认为实体本身以及如何组装实体实际上是两个职责。所以理想情况下最好将它们分配到不同的类中。但这也取决于。

于 2013-08-10T05:26:13.137 回答
0

真的是建议做 ddd 吗?

如果您没有内存存储库,但您的存储库有一个关系数据库,并且您希望与他们的雇主一起获得 1000 人怎么办?您是否要通过employeesRepository 调用进行1000 个查询...?

我会使用 NHibernate 或任何 ORM 来帮助实现 personRepository。使用 NHibernate,我将使用与此类似的 Hibernate Query:“from Person join fetch Employer”,它将在每个“Person”实例中加载一个“Employer”实例,只有一个 SQL 查询。

是否违反 DDD ?

于 2011-03-20T18:25:14.303 回答