Должны ли сущности реализовывать интерфейсы?
Лично у меня нет моих сущностей, реализующих интерфейсы. Для Task
класс я бы не имел ITask
которые просто имеют те же свойства, определенные на нем.
Я видел, как это делалось несколько раз, поэтому мне интересно, откуда этот совет, и какие выгоды вы получаете от него.
Если вы используете ORM, то аргумент "Я могу изменить свой доступ к данным" не имеет смысла, так какая еще причина для этого?
ОБНОВИТЬ:
Хорошая мысль была высказана в комментариях о INotifyPropertyChanged
, Это не моя точка зрения - я говорю о том, чтобы иметь что-то вроде этого:
public interface ITask
{
int Id { get; set; }
string Description { get; set; }
}
public class Task : ITask
{
public int Id { get; set; }
public string Description { get; set; }
}
5 ответов
Я пошел по этому пути один раз (интерфейсы для объектов значения). Это была королевская боль в спине, я рекомендовал против нее. Общие аргументы для этого:
Насмешка: они являются ценными объектами. Нечего издеваться. Плюс насмешка в конечном итоге становится большой болью, чем написание компоновщика (на Java) или использование именованных аргументов в C#.
Просмотры только для чтения: я должен признать, что я все еще предпочитаю делать что-то неизменное по умолчанию, только делая его изменяемым, если это абсолютно необходимо.
Скрытая функциональность: как правило, эта сфера для меня.
Основным преимуществом этого является то, что это способ представить вашу сущность как версию "только для чтения" (если, конечно, ваш интерфейс не предоставляет сеттеров).
Мы проводим довольно много модульного тестирования и очень часто хотим высмеивать вещи, которые не тестируем. Хотя мне это не нравится, мы закончили тем, что использовали интерфейсы повсюду, потому что это намного легче насмехаться над вещами.
Теоретически большинство фальшивых фреймворков могут также дразнить нормальные классы, но на практике это вызывает у нас проблемы, потому что мы иногда делаем умные вещи с отражением, а тип фальсифицированного класса не совпадает с оригиналом. Так делаем:
var myTask = MyIoCProvider.Get<Task>();
var taskType = typeof(myTask);
Был непредсказуем. В то время как:
var myTask = MyIoCProvider.Get<ITask>();
var taskType = typeof(myTask);
Дает вам тип задачи, который определенно получен из ITask.
Таким образом, интерфейсы просто дают нам возможность сделать нашу систему более привлекательной.
Если вы думаете с точки зрения использования DomainEvents, то структуры данных, такие как задача, действительно должны реализовать интерфейс
public interface IDomainEvent
{
Guid EventId { get; }
Guid TriggeredByEvent { get; }
DateTime Created { get; }
}
public class OrderCancelledEvent : IDomainEvent
{
Guid EventId { get; set; }
Guid TriggeredByEvent { get; set; }
DateTime Created { get; set; }
// And now for the specific bit
int OrderId { get; set; }
}
Или аналогичным образом, если у вас есть общий уровень доступа к данным, который, возможно, должен принять стандартный базовый класс IEntity, но у меня не было бы интерфейса для каждого типа, если бы это была просто структура данных, как вы описываете в своем посте.
Когда вы обрабатываете доменные объекты, которые фактически демонстрируют поведение, вы можете захотеть иметь интерфейс для модульного тестирования.
Я думаю, что некоторые программисты просто используют интерфейсы, потому что они слышали, что интерфейсы хороши, поэтому перестали использовать их везде, не задумываясь о реальных плюсах и минусах.
Лично я никогда не использую интерфейсы для сущностей, которые представляют только часть данных, например, строку db.