Это ддд анти-паттерн? - PullRequest
2 голосов
/ 15 июля 2010

Является ли нарушением нехватки персистентности внедрение интерфейса репозитория в объект Entity. Не используя интерфейс, я ясно вижу проблему, но при использовании интерфейса действительно проблема? Является ли приведенный ниже код хорошим или плохим шаблоном и почему?

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 ]

1 голос
/ 15 июля 2010

Это не совсем хорошая идея, но она может подойти для некоторых ограниченных сценариев. Меня немного смущает ваша модель, так как мне трудно поверить, что Address - это ваш совокупный корень, и поэтому не было бы обычным иметь полноценное хранилище адресов. Исходя из вашего примера, вы, скорее всего, используете шлюз табличных данных или dao, а не репозиторий.

Я предпочитаю использовать средство отображения данных для решения этой проблемы (ORM или аналогичное решение). По сути, я бы воспользовался своим ORM, чтобы рассматривать адресную книгу как лениво загруженное свойство совокупного корня «Контакт». Преимущество этого заключается в том, что ваши изменения могут быть сохранены, пока объект связан с сеансом.

Если бы я не использовал ORM, я бы все же предпочел, чтобы конкретная реализация репозитория Contact установила свойство резервного хранилища AddressBook (список или что-то еще). Я мог бы установить в репозитории это перечисление для прокси-объекта, который знает о другом хранилище данных и загружает его по требованию.

0 голосов
/ 22 февраля 2013

Поскольку прошло 2 года с тех пор, как я задал вопрос и вопрос несколько неправильно понял, я попытаюсь ответить на него сам.

Перефразированный вопрос: "Должны ли классы бизнес-сущностей быть полностью невежественными?"

Я думаю, что классы сущностей должны быть полностью невежественными, потому что вы будете создавать их во многих местах в своей кодовой базе, так что быстро станет грязно, когда всегда придется вставлять класс Repository в конструктор сущностей, и при этом он не выглядит очень чистым.Это становится еще более очевидным, если вам нужно ввести несколько репозиториев.Поэтому я всегда использую отдельный обработчик / класс обслуживания для выполнения заданий персистентности для сущностей.Эти классы создаются гораздо реже, и вы обычно лучше контролируете, где и когда это происходит.Классы сущностей сохраняются как можно более легкими.

Теперь у меня всегда есть 1 корень агрегирования для репозитория, и если мне нужна дополнительная бизнес-логика, когда сущности выбираются из репозиториев, я обычно создаю 1 ServiceClass для корня агрегата.

Взяв подправленный пример кода в вопросе, поскольку это был плохой пример, я бы сделал это сейчас так:

Вместо:

public class Contact
{
    private readonly IContactRepository _contactRepository;

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

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

Iсделать это так:

public class Contact
{

}

public class ContactService
{
    private readonly IContactRepository _contactRepository;

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

    public void Save(Contact contact)
    {
        _contactRepository.Save(contact);
    }
}
0 голосов
/ 22 февраля 2013

Обычно, когда вы следуете DDD, вы всегда оперируете целым агрегатом.Репозиторий всегда возвращает вам полностью загруженный агрегатный корень.

Не имеет особого смысла (по крайней мере, в DDD) писать код, как в вашем примере.Агрегат Contact всегда будет содержать все адреса (если он понадобится им для его поведения, что я сомневаюсь, если честно).

Так, как правило, ContactRepository предполагает построить весь агрегат Contact, где Address является объектом илискорее всего, объект значения внутри этого агрегата.

Поскольку Address - это объект сущности / значения, который принадлежит (и поэтому управляется) агрегату контактов, у него не будет собственного репозитория, поскольку вы не собираетесь управлять объектами.которые принадлежат агрегату за пределами этого агрегата.

Резюме: всегда загружать весь Контакт и вызывать его метод поведения, чтобы что-то делать с его состоянием.

0 голосов
/ 29 июля 2010

Вы можете ввести функцию загрузки извне.Для этого пригодится новый тип Lazy<T> в .NET 4.0:

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

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

Также обратите внимание, что IEnumerable<T> s может в любом случае быть ленивым, когда вы получаете их от поставщика запросов.Но для любого другого типа вы можете использовать Lazy<T>.

...