Является ли использование индивидуальных интерфейсов с объектами домена хорошей или плохой практикой? Зачем? - PullRequest
26 голосов
/ 05 мая 2009

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

Например:

Объект домена Учетная запись:

public class Account : IAccount
{
     public string Name {get;set;}
     //...some more fields that are also in IAccount
     public decimal Balance {get;set;}
}

И это соответствует интерфейсу

public interface IAccount
{
   string Name {get;set;}
   //... all the fields in Account
   decimal Balance {get;set;}
}

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

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

Сначала было заявлено, что эти интерфейсы обеспечивают «развязку», но я против, потому что интерфейсы имеют взаимно-однозначное отношение с объектами домена, что они на самом деле не обеспечивают развязки, что означает изменение интерфейса изменение сущности домена и наоборот.

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

Так что мне любопытно:

Зачем вам один-к-одному интерфейсы для сущностей вашего домена?

Почему бы и нет?

Почему это хорошая или плохая практика?

Спасибо за чтение!

РЕДАКТИРОВАТЬ : Я должен отметить, что я использую интерфейсы все время, и я верю, что, если он будет вызван, я буду использовать интерфейс без промедления. Но я конкретно имею в виду доменные сущности с однозначными интерфейсами.

Ответы [ 6 ]

9 голосов
/ 05 мая 2009

Это плохая практика, как описано, но ...

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

Чтобы использовать ваш пример, интерфейс IAccount, который вы описываете, предоставляет геттеры и сеттеры для объекта Account; кажется немного странным и маловероятным, что все, что использует Учетную запись, будет нуждаться в установке баланса в учетной записи, и что это подразумеваемое разрешение указывается на этом уровне интерфейса. Нет ли в вашей системе места, где вы хотите просто проверить, но не установить остаток на Счете?

7 голосов
/ 05 мая 2009

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

Но что, если у вас было, например:

public class Account : IAccount { ... }       // Usual account, persistent
public class MockAccount : IAccount { ... }   // Test mock object
public class TransAccount : IAccount { ... }  // Account, not persistent
public class SimAccount : IAccount { ... }    // Account in a performance sim

и так далее?

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

5 голосов
/ 05 мая 2009

В общем, если мои классы не будут частью шаблона проектирования, такого как Стратегия или Посетитель, я не добавляю интерфейсы.

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

interface SomeStrategy {
   void doSomething(StrategyData data);
}

interface StrategyData {
   String getProperty1();

   String getProperty2();
} 

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

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

4 голосов
/ 11 мая 2009

Интерфейсы «один к одному» на объектах являются анти-шаблоном

Джеймс Грегори выразился лучше меня здесь .

1 голос
/ 17 июля 2013

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

0 голосов
/ 26 июня 2012

Почему этот провалился?

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

Фундаментальным примером является идентификатор (object.Id) для объекта, он будет отличаться в зависимости от того, где вы храните этот объект, и ответственность за его создание может или не может лежать в реализации данных позже. В SQL Server вы можете использовать автономный номер, но в хранилище таблиц Azure вы можете использовать Guid, но вам не нужно менять бизнес-логику приложения, поскольку вы меняете место хранения своих данных.

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

Мы бы повторили тот же аргумент о том, каким должен быть адрес, если бы у нас не было IAddress, новые программисты переписывали бы вещи для кредитных карт, если бы не ICreditCard.

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

Для большинства паттернов есть место, даже клеветнический синглтон, что означает, что он не является "анти-паттерном", по крайней мере, как предполагает термин.

...