我正在尝试构建一个框架,允许人们通过实现接口来扩展我们的核心功能。下面是这个界面的一个愚蠢的例子。
public interface MyInterface
{
IData GetData(string p1, char p2, double p3);
}
最近,我们决定修改这个界面(我知道我不应该破坏依赖代码,但事实是我们还没有任何第三方实现这个界面,所以我们有机会“做” - “正确实现此接口。”
我们需要在此界面中再添加2个参数才能使我们的软件正常工作。我们想到的两种方式就是将它们添加到签名中:
public interface MyInterface
{
IData GetData(string p1, char p2, double p3, bool p4, DateTime p5);
}
或通过创建像这样的参数对象
public class MyParameters
{
public bool p4 { get; set; }
public DateTime p5 { get; set; }
}
并将它们添加到方法的末尾,如下所示:
public interface MyInterface
{
IData GetData(string p1, char p2, double p3, MyParameters p4);
}
我正在寻找某种指导,以哪种方式是“最”正确的方法。我可以看到这两个类别的优点和缺点,但我不希望我的偏见导致我走错路。
我的一些主要担忧是:
我甚至不知道在线询问什么问题以获得此问题的指导。我有一种感觉,答案是“它取决于”(关于如何将相关的p1-p5与GetData()函数的目的相关联),但有人可以指出我应该要求的一系列问题来帮助我评估一种解决方案是否优于另一种解决方案?
答案 0 :(得分:2)
为什么不一直走:
public Interface IParameters
{
string p1 {get; set;}
char p2 {get; set;}
double p3 {get; set;}
bool p4 { get; set; }
DateTime p5 { get; set; }
}
public interface MyInterface
{
IData GetData(IParameters p);
}
答案 1 :(得分:2)
让我试着回答这个问题。让我们评估您的选择:
1)如果以下界面
public interface MyInterface
{
IData GetData(string p1, char p2, double p3);
}
坏了:
a)并且根本不应该使用,那么你应该强制实现者重写它。所以改变方法定义。
public interface MyInterface
{
IData GetData(something else);
}
b)但你只需要鼓励用户使用新的定义,然后你可以创建一个新的重载,告诉他们第一个过时。
public interface MyInterface
{
//xml to tell them this is deprecated.
IData GetData(string p1, char p2, double p3);
IData GetData(string p1, char p2, double p3, and whatever);
}
关于你的新定义,没有任何人可以在不知道模型的情况下提供一站式解决方案,但你会问自己,
I)“参数本身是否可以代表一个单独的实体?它是否意味着在现实世界中有一个单位的参数?”如果是这样,那就这样做吧。如果没有,不要。当你处于这种两难境地时,我认为你应该依赖于如此抽象的思维。我不确定俱乐部bool p4
和DateTime p5
的重点是什么。你应该把那些本身代表现实生活中的东西的参数扼杀。如果没有那些组合是有意义的,那么就这样离开。你将更加成功地将这种俱乐部留给这种合乎逻辑的思维方式。请注意,您将自己的定义留给其他程序员,为了简化他们的工作,您的方法签名应该非常符合逻辑。
II)班级可以做更多的事情,而不仅仅是持有一组数据吗?班级应该是选择。
III)我是否只需要控制类定义而不是它的实现?在这种情况下,只需定义输入的公共接口,并将实现留给客户。
IV)我接口的未来修改是否应该破坏现有的实现?重载是您的最佳选择。
让我们说你有两个选择,让签名变平,或者去俱乐部。
1)没有夜总会:
a)减少代码,减少另一层。
b)无需向公众公开其他课程。
2)使用夜总会:
a)更好地理解模型以进入功能 - 你的意图很明确。
b)如果您需要添加构造新创建的类的可选细节,将来可以轻松扩展。假设你有一个班级
class Input {
string p1; char p2; double p3;
public Input(string p1, char p2, double p3){
}
}
和界面
public interface MyInterface
{
IData GetData(Input p1);
}
现在您可能想要添加可选的详细信息,例如bool和DateTime。因为它们是可选的,所以你不必在构造函数中强制它。您仍然可以使用相同的构造函数,并在构造函数外部为用户提供修改权限。
class Input {
string p1; char p2; double p3; bool p4; DateTime p5;
public Input(string p1, char p2, double p3){
}
}
界面仍然可以是相同的。正如我所说,推导出这类任何东西的动力很遗憾地取决于你的模型。简而言之,如果分组可能意味着什么,那就把它变成一个类或接口(取决于谁来控制逻辑)。