Active Records против Repository - плюсы и минусы?

Используя ActiveRecord, вы можете определить такой класс:

class Contact
{
  private String _name;
  public String Name
  {
    get { return _name; }
    set 
    { 
      if (value == String.IsNullOrWhiteSpace())
        throw new ArgumentException(...);
      else
        _name = value;
    }
  }

  public Boolean Validate() { ... /* check Name is unique in DB */  }

  public Boolean Save() { ... }

  public static List<Contact> Load() { ... }
}

Несмотря на то, что это красиво и просто, я обнаружил, что мои классы сильно раздуваются из-за большого количества выполняемой логики!

Используя многоуровневый / доменный дизайн, вы можете определить тот же класс, например:

class Contact
{
    [Required(AllowEmptyStrings=false)]
    public String Name { get; set; }
}

class ContactService : IService
{
    public List<Contact> LoadContacts() { return (new ContactRepository()).GetAll(); }
    public Contact LoadContact(int id) { return (new ContactRepository()).GetById(id); }
    public Boolean SaveContact(Contact contact)
    {
        if (new ContactValidator().Validate(contact))
            new ContactRepository().Save(contact);
    }
}

class ContactRepository : IRepository
{
    public List<Contact> GetAll() { ... }
    public Contact GetById(int Id) { ... }
    public Boolean Save(Contact contact) { ... }
}

class ContactValidator : IValidator
{
    public Boolean Validate(Contact contact) { ... /* check Name is unique in DB */ }
}

class UnitOfWork : IUnitOfWork
{
    IRepository _contacts = null;
    public UnitOfWork(IRepository contacts) { _contacts = contacts; }
    public Commit() { _contacts.Save(); }
}

Как это было перенесено с Active Record => многоуровневый дизайн?

  • Проверка уровня сущности в средстве установки имени => остается (возможность через DataAnnotation)
  • Проверка бизнес-логики / правил (уникальное имя) => перенесено из объекта в новый отдельный ContactValidator
  • Логика сохранения => перемещена в отдельный класс шаблона репозитория (также с UnitOfWork)
  • Логика загрузки => перенесена в отдельный репозиторий
  • Взаимодействие с репозиторием осуществляется через новую службу ContactService (которая будет обеспечивать использование ContactValidator, ContactRepository, UnitOfWork и т. Д. - в отличие от того, чтобы позволить вызывающему абоненту расслабиться с помощью ContactRepository!).

Я ищу одобрение / предложения коллег по этому многоуровневому дизайну - я обычно не занимаюсь дизайном за пределами типа Active Record! Любой комментарий приветствуется.

NB. Этот пример намеренно прост (UnitOfWork на самом деле не используется, и создание репозитория / валидатора будет обрабатываться по-другому).


person Matt    schedule 29.06.2011    source источник


Ответы (3)


Это действительно зависит от того, насколько сложна логика вашей предметной области. Например, если я писал простой блог, то с активной записью все в порядке, в основном приложение сохраняет и загружает данные. Его простой и активный шаблон записи - правильный инструмент для работы.

Однако если бы я писал программное обеспечение для транспортной компании, в которой существует множество сложных бизнес-правил и процессов, то использовал бы шаблон репозитория вместе с другими Шаблоны Domain Driven Design в конечном итоге обеспечат гораздо более удобный в сопровождении код.

При проектировании, ориентированном на предметную область, вы должны использовать шаблон спецификации для достижения своей валидации.

person g.foley    schedule 25.08.2011

У обоих подходов есть свои плюсы и минусы.

Представьте, что вы передаете объект в стиле Active Record куда-то (глубоко внутри BL). Вы можете прочитать это, вы можете изменить это, вы можете СОХРАНИТЬ. В этом случае эта часть BL связана только с интерфейсом вашей сущности. В многоуровневой архитектуре вам нужно каким-то образом передать репозиторий этому коду. Вы бы либо передали его явно, либо использовали IoC-контейнер - на ваше усмотрение.

Другой момент заключается в том, что когда у вас есть концепция репозитория, вы можете легко определить такие концепции, как у нас-есть-новый-объект-в-репозитории или один-объект-был-удален-из-репозитория, которые в основном довольно полезные уведомления, если вы работаете с распределенной средой.

person Andrey Agibalov    schedule 19.07.2011

Эта статья кажется хорошим и кратким описанием обоих: https://hashnode.com/post/which-design-pattern-do-you-prefer-active-record-or-repository-cilozoaa5016o6t53mhsdu6nu

Одна вещь, которую я хотел бы добавить, заключается в том, что это не просто «активная запись хороша, когда ваши потребности в постоянстве просты, а репозиторий хорош, когда ваши потребности в постоянстве сложны». Выбор паттерна здесь гораздо больше связан с тем, как вы относитесь к Закону Деметры. Если вы хотите, чтобы разные части вашей архитектуры были полностью разделены, чтобы кто-то мог понять одну часть, не понимая другую, тогда вам нужен Закон Деметры. Тем не менее, я думаю, особенно на ранних этапах проекта, когда спецификация может измениться, ОЧЕНЬ опасно слишком зацикливаться на такого рода абстракциях. Не сомневайтесь в будущих сопровождающих вашего проекта, они могут быть умными и должны уметь думать о нескольких вещах одновременно, а если они не могут, то у вас могут возникнуть более серьезные проблемы, которые нельзя предотвратить с помощью шаблона репозитория. .

person olleicua    schedule 01.02.2018