#c# #oop #generics #collections #interface
Вопрос:
Я пытаюсь смоделировать проблему таким образом, чтобы:
- Расписание.Коллекция продуктов может состоять как из: iProducts, так и из IProductsWithConfig
- ProductWithConfig.Коллекция конфигурации может состоять только из iProducts, но не IProductsWithConfig
И я немного застрял — как сейчас (ниже) Я не могу запретить добавление/включение IProductsWithConfig в ProductWithConfig.Конфигурация. Есть идеи, как это элегантно закодировать?
interface ISchedule
{
IEnumerable<IProduct> Products { get; set; }
}
interface IProductWithConfig : IProduct
{
IEnumerable<IProduct> Config { get; set; }
}
interface IProduct
{
int Id { get; set; }
}
Комментарии:
1. Я не знаю, как это вписалось бы в ваш дизайн, но если бы у вас был другой интерфейс, который наследует
IProduct
, скажемIPlainProduct
, то это былоis-a IProduct
бы, но нетis-a IProductWithConfig
… и ты мог быIEnumerable<IPlainProduct> Config { get; set; }
2. @Fildor но IPlainProduct будет пустым интерфейсом, который наследуется от IProduct?
3. Может быть. Но в этом нет ничего плохого.
4. На самом деле, я думаю, что пункт 2 нарушает Принцип замены Лискова, если я не ошибаюсь.
5. В основном проблема здесь в следующем: вы разработали «наличие конфигурации», подразумевающее «быть потенциальным элементом конфигурации». Но в вашем втором требовании вы делаете «наличие конфигурации» и «быть конфигурацией» односторонним эксклюзивом. И размышляя об этом и моем решении выше: этого может быть даже недостаточно. Что делать, если у вас есть класс, который реализует оба интерфейса (что абсолютно законно)? …
Ответ №1:
Идея наследования заключается в том, что вы можете использовать любую производную версию IProduct в любой ситуации, когда вам требуется IProduct. Каждый экземпляр класса, реализующего IProductWithConfig, по определению является экземпляром, реализующим IProduct. Комментарий, который сделал Фильдор, имеет смысл: сделайте IProduct абстрактным и создайте из него нового потомка.
Или вы можете скрыть конфигурацию общедоступных свойств и предоставить их с помощью нескольких методов, таких как Add(продукт) и IEnumerable только для чтения. Затем вы можете контролировать, какие объекты добавляются в коллекцию.
Комментарии:
1. Я надеялся, что смогу использовать какой-нибудь трюк с co/contra-дисперсией, с которой я еще не так хорошо знаком.
2.@adam.k противоположность или несоответствие просто удерживает вас от присвоения a
List<IDerivedFromIProduct>
вашемуIEnumerable<IProduct>
, но я могу с радостью добавить объект к этому перечислимому до тех пор, пока онis-a
IProduct
. Это означает, что где-то в дереве он реализует этот интерфейс.