2010-02-28 2 views
29

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

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

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

по выполнению пользователя (Реализовано в LinqToSql Data Access Layer):

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 Data Access Layer):

[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, не в настоящее время есть лучший образец.

ответ

25

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

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

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

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

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

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

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

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

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

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

+0

@Aaronaught: Ok для ORM specific, теперь предположим, что я использую FullText Features, я буду использовать Lucene.NET, которые также используют атрибуты. И насколько я знаю, нет способа использовать внешнее сопоставление атрибутов, например FluentNhibernate. Итак, каков наилучший подход для того, чтобы мои объекты домена были истинными POCOs? Может быть, интерфейсы работают таким образом? –

+0

@Yoann. B: Я не знал, что Lucene.NET использовал атрибуты декоратора; это определенно не требует их. Если вы хотите использовать их, то у вас есть два варианта: либо (a) сделать вашу модель домена зависимой от Lucene.NET, которая кажется плохой идеей (что, если вы хотите использовать SQL FTS вместо? Что, если будущая версия Lucene.NET поддерживает POCOs?) Или (b) перемещает ваши объекты поиска и репозитории в другое пространство имен/сборку и использует такой инструмент, как AutoMapper, для преобразования их в объекты домена. В любом случае, я не думаю, что создание интерфейсов для объектов очень помогло бы. – Aaronaught

+0

@Aaronaught: Вы сказали, что Lucene.NET не требует атрибутов? о другом вопросе, который я разместил (http://stackoverflow.com/questions/2356593/lucene-net-and-poco-entities), но как вы обходитесь без использования атрибутов с Lucene.NET? –

1

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

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

+0

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

+1

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

6

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

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

1

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

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

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

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

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