Я наткнулся на эту проблему, которую я не могу решить должным образом. Вот некоторые пояснения.
Код
У меня есть эти классы продуктов:
public abstract class Product
{
public int BaseParam {get;set;}
}
public class SpecificProductA : Product
{
public int ParamA {get;set;}
}
public class SpecificProductB : Product
{
public int ParamB {get;set;}
}
И у меня есть эти потребительские классы:
public interface IConsumer
{
void Consume(Product product);
}
public class ConcreteConsumerA : IConsumer
{
public void Consume(Product product)
{
/* I need ParamA of SpecificProductA */
}
}
public class ConcreteConsumerB : IConsumer
{
public void Consume(Product product)
{
/* I need ParamB of SpecificProductB */
}
}
Проблема
Мне нужны конкретные реализации интерфейса IConsumer для доступа к определенным частям Продукта. ConcreteConsumerA сможет потреблять только ProductA, а ConcreteConsumerB может потреблять только ProductB. Это разрушает прекрасную абстракцию, которая была у меня с Consumer & Product.
Решение 1. Трансляция
Первое и очевидное, что можно сделать, это преобразовать экземпляр продукта в конкретный продукт. Это работает, но не идеально, так как я полагаюсь на среду выполнения, чтобы выдавать любые ошибки, если что-то не так с типом.
Решение 2. Прерывание наследования классов товаров
Другое решение состояло в том, чтобы разорвать наследование Продукта примерно так:
public class Product
{
public int BaseParam {get;set;}
public SpecificProductA ProductA {get;set;}
public SpecificProductB ProductB {get;set;}
}
public class SpecificProductA
{
public int ParamA {get;set;}
}
public class SpecificProductB
{
public int ParamB {get;set;}
}
Решение 3. Универсальные методы
Я также могу сделать интерфейс IConsumer универсальным следующим образом:
public interface IConsumer<TProduct> where TProduct: Product
{
void Consume(Product product);
}
public class ConcreteConsumerA : IConsumer<SpecificProductA>
{
public void Consume(SpecificProductA productA)
{
/* I now have access to ParamA of SpecificProductA */
}
}
public class ConcreteConsumerB : IConsumer<SpecificProductB>
{
public void Consume(SpecificProductB productB)
{
/* I now have access to ParamA of SpecificProductB */
}
}
Однако, подобно раку, этот общий интерфейс теперь распространяется на всю программу, что тоже не идеально.
Я не уверен, что здесь не так и какое правило было нарушено. Возможно, это проблема дизайна, которую нужно изменить. Есть ли лучшее решение, чем те, которые предназначены для решения этой проблемы?
ReadOnlyDictionary<string, int>
, гдеKey
— это текущее имя свойства? Таким образом, существующие свойства могут быть прочитаны изReadOnlyDictionary
, но также все свойства могут быть прочитаны, даже из базового класса, черезReadOnlyDictionary
. - person mjwills   schedule 22.03.2018Configuration
, казалось разумным предположить, что это была ваша проблемная область. Это действительно продукты вместо этого? Или вы ищете решение, которое справляется с обоими? - person mjwills   schedule 22.03.2018