Должны ли доменные объекты быть представлены как интерфейсы или как простые объекты? - PullRequest
31 голосов
/ 01 марта 2010

Должны ли доменные объекты быть представлены как интерфейсы или как простые объекты?

Интерфейс пользователя:

public interface IUser
{
    string FirstName { get; set; }
    string LastName { get; set; }
    string Email { get; set; }
    Role Role { get; set; }
}

Реализация пользователя (реализована в уровне доступа к данным LinqToSql):

public class User : IUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public Role Role { get; set; }
}

Реализация пользователя (реализована в уровне доступа к данным NHibernate):

[NHibernate.Mapping.Attributes.Class]
public class User : IUser
{
    [NHibernate.Mapping.Attributes.Property]
    public string FirstName { get; set; }

    [NHibernate.Mapping.Attributes.Property]
    public string LastName { get; set; }

    [NHibernate.Mapping.Attributes.Property]
    public string Email { get; set; }

    [NHibernate.Mapping.Attributes.Property]
    public Role Role { get; set; }
}

это только иллюстрирует некоторые специфические реализации DAL, в настоящее время нет лучшего образца.

Ответы [ 4 ]

27 голосов
/ 01 марта 2010

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

Считайте, что модель предметной области является моделью человека. Бизнес / услуга / документ - это, буквально, домен. Большинство из нас разрабатывают программное обеспечение для одного бизнеса или цели. Если модель предметной области меняется, это происходит потому, что изменились бизнес-правила, и поэтому старая модель предметной области больше не действительна - нет смысла сохранять старую модель рядом с новой.

Дебаты явно не черно-белые. Возможно, вы разрабатываете программное обеспечение, которое сильно настроено на нескольких клиентских сайтах. Возможно, вам действительно потребуется реализовать разные наборы бизнес-правил одновременно и одновременно иметь реальную необходимость вписать их в единую архитектуру. Но, по моему опыту, по крайней мере, эти случаи являются скорее исключением, чем правилом, и хотя я обычно не люблю этот термин, это может быть случай, когда вам следует подумать про себя: ЯГНИ .

Доступ к данным - это общая область, в которой вам нужны более качественные абстракции ( постоянное невежество ). В вашем примере у вас есть атрибуты NHibernate в вашем классе модели. Но добавление атрибутов постоянства делает его уже не настоящим классом домена, поскольку оно вводит зависимость от NHibernate. NHibernate и Fluent NHibernate поддерживают сопоставление POCO с использованием объявления внешнего сопоставления вместо атрибутов в классе данных, и это, как правило, является предпочтительным подходом при использовании ORM, таких как NHibernate или EF4, поскольку это нарушает зависимость между моделью персистентности и моделью домена.

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

Некоторые типы объектов, которые вы хотели бы выставить как интерфейсы:

  • Репозитории, отвечающие за загрузку / сохранение объектов домена;
  • Плагины / расширения для вашей программы;
  • Просмотр / модели презентаторов, чтобы можно было подключать различные интерфейсы;
  • Абстрактные типы данных со множеством реализаций (массив, список, словарь, набор записей и таблица данных - это последовательности AKA IEnumerable);
  • Абстрактные операции со многими возможными алгоритмами (сортировка, поиск, сравнение);
  • Модели связи (те же операции по TCP / IP, именованные каналы, RS-232);
  • Все, что связано с платформой, если вы планируете развернуть несколько (Mac / Windows / * nix).

Это ни в коем случае не полный список, но он должен осветить здесь основной принцип, который заключается в том, что для абстракций интерфейса лучше всего подходят вещи, которые:

  1. Зависит от факторов, которые могут быть вне вашего контроля;
  2. Вероятно, изменится в будущем; и
  3. Горизонтальные элементы (используются во многих частях приложения / архитектуры).

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

7 голосов
/ 01 марта 2010

Интерфейсы обычно считаются «контрактами» и поэтому определяют поведение. Другое основное использование - макетирование, чтобы вы могли предоставлять доменные объекты, которые были макетами, а не исходили из определенного источника данных (и имели зависимости от этого источника).

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

2 голосов
/ 21 января 2016

Сущность в большинстве случаев не следует вводить.

Сущность явно определяет идентичность, уникальную для других сущностей того же типа. У сущности Order уже должен быть идентификатор, отличный от всех других сущностей Order в системе. Это также может нанести ущерб идентичности объекта, если вы смоделируете его с помощью наследования.

Например: скажем, у вас есть Customer и вы используете Customer как AmericanCustomer. Приведите все это поведение и состояние, необходимое для того, чтобы быть американским клиентом (подсказка: любит шоппинг!). Затем тот же самый Customer, с тем же именем, с теми же покупательскими привычками, - отправляется в Японию. Они все еще AmericanCustomer? Вы создаете новый JapaneseCustomer и копируете все данные, включая идентификатор этого клиента, в этот новый тип? Это может иметь последствия ..

Тот же самый клиент все еще любит делать покупки? Это может или не может быть правдой для JapaneseCustomer. И все же теперь внезапно в пределах одного забронированного рейса этот Customer изменился. Другие объекты в системе будут запрашивать тот же Customer, используя его уникальный идентификатор, и могут получить изображение объекта, отличное от ожидаемого (AmericanCustomer). Возможно, Клиент смоделирован вокруг национального происхождения вместо текущего местоположения. Это может решить некоторые из проблем, но также и ввести новые.

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

1 голос
/ 01 марта 2010

Простые объекты, если нет общего интерфейса для реализации, которая может измениться. Вот для чего нужны интерфейсы. Классы значений, такие как Money или Address, не попадают в эту категорию.

Ваш пример интерфейса не имеет никакого поведения, кроме getter / setter. Это не то, для чего нужны интерфейсы.

...