这是ddd反模式吗?

时间:2010-07-15 13:27:11

标签: repository domain-driven-design entities

将Entive对象注入存储库接口是否违反了持久性原则,就像这样。通过不使用接口我清楚地看到一个问题但是当使用接口时真的有问题吗?代码是好的还是坏的?为什么?

public class Contact
{
    private readonly IAddressRepository _addressRepository;

    public Contact(IAddressRepository addressRepository)
    {
        _addressRepository = addressRepository;
    }

    private IEnumerable<Address> _addressBook;
    public IEnumerable<Address> AddressBook
    {
        get
        {
            if(_addressBook == null)
            {
               _addressBook = _addressRepository.GetAddresses(this.Id);
            }
            return _addressBook;
        }
    }
}

4 个答案:

答案 0 :(得分:1)

这不是一个好主意,但对于某些有限的情况可能没问题。我对你的模型有点困惑,因为我很难相信Address是你的聚合根,因此拥有一个完整的地址存储库是不平凡的。根据您的示例,您实际上可能正在使用表数据网关或dao而不是存储库。

我更喜欢使用数据映射器来解决这个问题(ORM或类似的解决方案)。基本上,我会利用我的ORM将地址簿视为聚合根的“延迟加载”属性“Contact”。这样做的好处是,只要实体绑定到会话,就可以保存更改。

如果我没有使用ORM,我仍然希望具体的Contact存储库实现设置AddressBook后备存储(列表或其他)的属性。我可能将存储库设置为枚举到知道其他数据存储的代理对象,并根据需要加载它。

答案 1 :(得分:0)

您可以从外部注入加载功能。 .NET 4.0中的新Lazy<T>类型可以派上用场:

    public Contact(Lazy<IEnumerable<Address>> addressBook)
    {
        _addressBook = addressBook;
    }

    private Lazy<IEnumerable<Address>> _addressBook;
    public IEnumerable<Address> AddressBook
    {
        get { return this._addressBook.Value; }
    }

另请注意,当您从查询提供程序获取IEnumerable<T>时,Lazy<T>可能本质上是懒惰的。但对于任何其他类型,您可以使用{{1}}。

答案 2 :(得分:0)

通常,当您关注DDD时,您始终使用整个聚合操作。存储库始终返回一个完全加载的聚合根。

在您的示例中编写代码没有多大意义(至少在DDD中)。联系人聚合将始终包含所有地址(如果它的行为需要它们,我怀疑这是诚实的。)

所以通常ContactRepository假设你构建整个Contact聚合,其中Address是一个实体,或者很可能是这个聚合中的一个值对象。

因为Address是一个实体/值对象,它属于(并因此由其管理)Contact聚合,它将没有自己的存储库,因为您不应该管理属于此聚合之外的聚合的实体。

恢复:始终加载整个联系人并调用其行为方法以对其状态执行某些操作。

答案 3 :(得分:0)

自从我提出问题已经过去2年以来,这个问题有些误解我会尝试自己回答。

改述问题: “商业实体课程应该完全无情吗?”

我认为实体类应该是完全持久的无知,因为你会在代码库中将它们实例化很多位置,因此总是必须将Repository类注入实体构造函数,它看起来很干净。如果您需要注入多个存储库,这将变得更加明显。因此,我总是使用单独的处理程序/服务类来为实体执行持久性作业。这些类的实例化程度要低得多,您通常可以更好地控制发生这种情况的地点和时间。实体类尽可能保持轻量级。

我现在总是拥有1个Repository pr聚合根,如果在从存储库中提取实体时需要一些额外的业务逻辑,我通常会为聚合根创建1个ServiceClass。

通过对问题中的代码进行调整,因为这是一个不好的例子,我现在会这样做:

而不是:

public class Contact
{
    private readonly IContactRepository _contactRepository;

    public Contact(IContactRepository contactRepository)
    {
        _contactRepository = contactRepository;
    }

    public void Save()
    {
        _contactRepository.Save(this);
    }
}

我这样做:

public class Contact
{

}

public class ContactService
{
    private readonly IContactRepository _contactRepository;

    public ContactService(IContactRepository contactRepository)
    {
        _contactRepository = contactRepository;
    }

    public void Save(Contact contact)
    {
        _contactRepository.Save(contact);
    }
}