Я хотел бы добавить одну вещь: это не просто «активная запись хороша, когда ваши потребности в персистентности просты, а репозиторий хорош, когда ваши потребности в персистентности сложны». Выбор паттерна здесь во многом зависит от того, как вы относитесь к Закону Деметры. Если вы хотите, чтобы разные части вашей архитектуры были полностью разделены, чтобы кто-то мог понять одну часть, не понимая другую, тогда вам нужен закон Деметры. Тем не менее, я думаю, что особенно в начале проекта, когда спецификация может измениться, ОЧЕНЬ опасно становиться слишком одержимым подобными абстракциями. Не пытайтесь угадать будущих сопровождающих вашего проекта, они могут быть умными, и они должны быть в состоянии думать о более чем одной вещи за раз, и если они не могут, то у вас могут возникнуть более серьезные проблемы, которые нельзя предотвратить с помощью шаблона 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 на самом деле не используется, и обновление Repository / Validator будет обрабатываться иначе).