Предположим, у меня есть различные объекты в моей модели (с использованием EF), например, Пользователь, Продукт, Счет-фактура и Заказ.
Я пишу пользовательский элемент управления, который может распечатывать сводки объектов сущностей в моем приложении, где сущности принадлежат заранее определенному набору, в этом случае я говорю, что сводки пользователей и продуктов можно суммировать.
Все сводки будут иметь только идентификатор и описание, поэтому я создам простой интерфейс для этого:
public interface ISummarizableEntity {
public string ID { get; }
public string Description { get; }
}
Затем для рассматриваемых сущностей я создаю частичный класс, который реализует этот интерфейс:
public partial class User : ISummarizableEntity
{
public string ID
{
get{ return UserID.ToString(); }
}
public string Description
{
get{ return String.Format("{0} {1} is from {2} and is {3} years old", FirstName, LastName, Country, Age); }
}
}
public partial class Product: ISummarizableEntity
{
public string ID
{
get{ return ProductID.ToString(); }
}
public string Description
{
get{ return String.Format("{0} weighs {1}{2} and belongs in the {3} department", ProductName, WeightValue, WeightUnit, Department); }
}
}
Таким образом, мой пользовательский элемент управления / частичное представление может просто связываться с любой коллекцией ISummarizableEntity и вообще не должен интересоваться источником. Мне сказали, что интерфейсы не должны использоваться в качестве типов данных, но я не получил больше информации, чем это. Насколько я могу видеть, хотя интерфейсы обычно описывают поведение, простое использование свойств само по себе не является анти-паттерном, так как в любом случае свойства являются просто синтаксическим сахаром для методов получения / установки.
Я мог бы создать конкретный тип данных и сопоставить его с сущностями, но не вижу преимущества. Я мог бы заставить объекты сущности наследоваться от абстрактного класса, а затем определить свойства, но затем я блокирую сущности для дальнейшего использования, поскольку у нас не может быть множественного наследования. Я также открыт для любого объекта ISummarizableEntity, если бы я хотел (очевидно, я бы переименовал интерфейс)
Решение, которое я использую в своем уме, является обслуживаемым, расширяемым, тестируемым и достаточно надежным. Вы можете увидеть здесь анти-паттерн?
EntitySummary
,User
и уProduct
каждого такой методpublic EntitySummary GetSummary()
?Ответы:
Интерфейсы не описывают поведение. Иногда наоборот.
Интерфейсы описывают контракты, такие как «если я хочу предложить этот объект любому методу, который принимает ISummarizableEntity, этот объект должен быть сущностью, которая может суммировать себя» - в вашем случае это определяется как возможность вернуть идентификатор строки и описание строки.
Это идеальное использование интерфейсов. Здесь нет анти-паттерна.
источник
List
списком, который не ведет себя как список?Вы выбрали лучший путь для этого дизайна, потому что вы определяете определенный тип поведения, который потребуется для нескольких различных типов объектов. Наследование в этом случае подразумевает общие отношения между классами, которые на самом деле не существуют. В этом случае сочетаемость предпочтительнее наследования.
источник
Следует избегать интерфейсов, которые несут только свойства , так как:
Здесь вы смешиваете две проблемы:
Сводка состоит из двух строк: идентификатора и описания. Это простые данные:
Теперь, когда вы определили, что такое сводка, вы хотите определить контракт:
Обратите внимание, что использование интеллекта в геттерах - это анти-паттерн, и его следует избегать: вместо этого его следует размещать в функциях. Вот как выглядят реализации:
источник