我刚刚开始使用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
答案 0 :(得分:23)
这不是对DDD的可怕违反,这是一种可怕的违反......好吧......它只是非常可怕(我说的是这个舌头在脸颊):)。
首先,您的实体变得依赖于拥有存储库......这并不理想。 理想情况下,您希望让您的存储库创建Person,然后为其分配在当前域上下文中有效的所有内容。
因此,当您需要一个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;
}
}
答案 1 :(得分:5)
问题的答案是标准取决于。
根据经验,不要这样做。保持您的实体不引用存储库。 [把实用的帽子放在]在一些罕见的,非常罕见的情况下,你有一个非常非常好的理由这样做,而不是添加一个大的评论解释你为什么这样做并做到这一点 - 添加引用或使用Double Dispatch来传递存储库[ hat off ]
此外,如果您希望遵循DDD原则,强烈建议您访问域专家和迭代的开发过程(请参阅Eric Evans - what i've learned since the book)。
使用您的域专家,您应该定义边界上下文,最重要的是聚合及其聚合根及其实体和值对象。一开始沿着DDD路走下去并不容易,但是rewords是滔滔不绝的。
关于您发布的代码的一些事项:
不建议在您的实体上安装公共设置器。使用方法代替更好地表达意图。
如果在未初始化_employer字段的情况下创建了人员实例,则Employer属性的getter将返回null。如果然后将Employer属性的值设置为null,则对getter的下一次调用将返回非null值。这可能是您班级用户意料之外的事。
设置Person的雇主(通过公共设置者或公共方法)的呼叫者应该知道它要设置的确切公司实例,即使它是默认设置。也许调用者可以拥有对存储库的引用。
根据您的具体领域,公司可能是一个价值对象。在这种情况下,不是使用null初始化_employer,而是可以使用值对象的默认值对其进行初始化。如果你只有很少的公司(1-2)并且它们是不可变的并且没有特定的行为,情况就是这样。
答案 2 :(得分:3)
我认为很容易说实体不应该知道存储库,但很难将其付诸实践。特别是当聚合内部收集大量的vo时,我们必须重构它并将 add 等操作委托给一些实际充当存储库的域服务,以避免将整个集合加载到内存中的开销。
但我认为让实体知道存储库是不合理的。如果必须,请使用域名服务。我们还应该考虑存储库是否违反单一责任原则 - 它本应被视为聚合根的集合,而不是正常的工厂。
答案 3 :(得分:0)
这真的是推荐做ddd吗?
如果您没有内存存储库,但是存储库的关系数据库,并且您希望与其雇主一起获得1000人,该怎么办?你打算通过employerRepository调用来进行1000次查询......?
我会使用NHibernate或任何ORM来帮助实现personRepository。使用NHibernate,我将使用接近这个的Hibernate Query:“来自Person join fetch Employer”,它将在每个“Person”实例中加载一个“Employer”实例,只有一个SQL查询。
它是否违反DDD?
答案 4 :(得分:0)
首先,我认为实体本身以及如何组装实体实际上是2个职责。理想情况下,最好将它们分配到不同的类中。但这也取决于。