У меня проблема с дизайном, которую я не могу понять. Вот что у меня есть:
В общем, у меня есть два основных типа объектов Strikes и Options. Они были разделены на два интерфейса: IStrike и IOption.
Допустим, у IOption есть следующие поля, в действительности их примерно в 10 раз больше, но мы можем использовать следующие три для иллюстрации проблемы.
interface IOption
{
double Bid{get;set;}
double Ask{get;set;}
double ImpliedVol{get;set;}
}
interface IStrike
{
IOption Call{get;set;}
IOption Put{get;set;}
}
Теперь, это все хорошо, но, скажем, у меня есть следующий метод для выполнения некоторой "математики" над подразумеваемым IOption vol
public double SquareImpliedVol(IOption opt)
{
return Math.Pow(opt.ImpliedVol,2);
}
Опять же, не проблема, но когда я пишу какие-то фиктивные объекты для своих тестов, мне не ясно, нужно ли мне реализовать Bid и Ask. Я не знаю, но я бы не узнал об этом, если бы не знал смелости внутри SquareImpliedVol, что означает, что я пишу тесты для кода, что плохо.
Итак, чтобы исправить это, я мог бы создать еще один интерфейс IOptionImpliedVol, который просто содержит свойство ImpliedVol, и затем иметь наследование IOption от IOptionImpliedVol, например
interface IOption : IOptionImpliedVol
{
double Bid{get;set;}
double Ask{get;set;}
}
И тогда мы можем включить SquareImpliedVol
public double SquareImpliedVol(IOptionImpliedVol opt)
{
return Math.Pow(opt.ImpliedVol,2);
}
И мы великолепны. Я могу писать фиктивные объекты, и все мило. Кроме .... Я хочу написать метод, который будет работать с List, но единственные свойства, которые мне нужны из IStrike, это Call.ImpliedVol и Put.ImpliedVol. Я хочу создать что-то вроде
interface IStrikeImpliedVol
{
IOptionImpliedVol Call;
IOptionImpliedVol Put;
}
и тогда у меня тоже может быть
interface IStrike : IStrikeImpliedVol
{
IOption Call;
IOption Put;
}
За исключением того, что это не законно. Я чувствую, что должен быть какой-то шаблон проектирования, который я мог бы решить, но я застрял в какой-то паутине композиции и наследования.