我有一个我无法弄清楚的设计问题.这是我得到的:
一般来说,我有两种常见类型的对象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;}
}
Run Code Online (Sandbox Code Playgroud)
现在,这一切都很好,但是让我说我已经有了以下方法来对IOption隐含卷执行一些"数学"
public double SquareImpliedVol(IOption opt)
{
return Math.Pow(opt.ImpliedVol,2);
}
Run Code Online (Sandbox Code Playgroud)
同样,不是问题,但是当我为我的测试编写一些模拟对象时,我不清楚是否需要实现Bid和Ask.我没有,但我不知道除非我知道SquareImpliedVol里面的内容,这意味着我正在编写针对代码的测试,这很糟糕.
所以为了解决这个问题,我可以创建另一个只包含ImpliedVol属性的接口IOptionImpliedVol,然后让IOption继承自IOptionImpliedVol,就像这样
interface IOption : IOptionImpliedVol
{
double Bid{get;set;}
double Ask{get;set;}
}
Run Code Online (Sandbox Code Playgroud)
然后我们可以切换SquareImpliedVol
public double SquareImpliedVol(IOptionImpliedVol opt)
{
return Math.Pow(opt.ImpliedVol,2);
}
Run Code Online (Sandbox Code Playgroud)
而且我们很棒.我可以写模拟对象,一切都很甜蜜.除了....我想编写一个将在List上运行的方法,但我需要的唯一属性是IStrike,它是Call.ImpliedVol和Put.ImpliedVol.我想创造类似的东西
interface IStrikeImpliedVol
{
IOptionImpliedVol Call;
IOptionImpliedVol Put;
}
Run Code Online (Sandbox Code Playgroud)
然后我也可以
interface IStrike : IStrikeImpliedVol
{
IOption Call;
IOption Put;
}
Run Code Online (Sandbox Code Playgroud)
除非这不合法.我觉得必须有某种设计模式,我可以解决这个问题,但我陷入了某种组合和继承的网络.
我认为你的初始设计有两个接口是正确的.你说你必须知道何时设置Bid/Ask以及何时不在测试中设置它并且困扰你.
让我们试着从其他角度来看待它.你正在为某些功能编写一个测试(让我们再说SquareImpliedVol一遍).你知道正确实现这个功能应该只关心ImpliedVol属性,但不关心Bid/Ask所以你可以把它们留空.如果函数将失败并且未设置,Bid/Ask那么您的单元测试会发现问题 - 请高兴.当然,如果空Bid/Ask是不正确的Option对象状态,它会有所不同,但在您的情况下,这似乎不是问题.
换句话说,我会说,你写你对测试知识上应该如何具体的方法工作,没有什么错在这方面的知识和已经写入功能码相关的事实.