【发布时间】:2012-07-08 04:55:30
【问题描述】:
我将 API 定义为一个接口,我们将调用它 IFoo 并且我想定义一个方法 Bar()
此方法Bar() 将采用一个必需的参数,然后是任意数量的其他参数。这些其他参数的解释将取决于IFoo的实现者
对于这种情况,使用params 或使用Dictionary<String, Object> 来定义我的界面是否更合适,例如
public interface IFoo
{
bool Bar(String id, params Object[] params);
}
或者
public interface IFoo
{
bool Bar(String id, Dictionary<String, Object> params);
}
似乎前者对用户来说更容易调用,但后者的意图更明确,因为对于前者,您必须按特定顺序指定参数,以便实现正确解释它们,而对于后者你实际上是在做命名参数。
所以问题:
- 我应该使用哪种形式(以及为什么?) - 其中一种被认为是最佳做法而不是另一种?
- 我应该注意一种风格与另一种风格相比是否有特定的优势?其中之一是否被视为代码异味?
- 是否有替代模式可以以不同/更好的方式实现相同的目标?
作为记录,我知道 .Net 4.0 中的 named parameters 但此代码需要在 .Net 3.5 上编译,因此不能使用任何 .Net 4.0+ 功能
编辑
只是为了更详细地说明我的 IFoo 和 Bar() 方法实际上代表什么,因为有人问了。
IFoo 代表一些存储子系统,Bar() 实际上是一个创建操作。根据存储子系统,Bar() 可能不需要除 ID 以外的参数,也可能需要许多参数。
编辑 2
因此,为了回应@Kirk Woll 的评论和@Fernando 的回答,这里有更多信息。
我可能永远不会自己调用IFoo.Bar(),这个接口是开源框架的一部分。第 3 方开发人员将实现IFoo,最终用户将调用它的特定实例,拥有IFoo 的目的是让用户更容易在存储子系统之间迁移他们的应用程序,因为他们可以编码到接口而不是比具体的实现尽可能人性化。
在最简单的情况下,底层存储子系统只有一种存储形式,因此除了 ID 之外不需要其他参数。在复杂的情况下,存储子系统可以允许多种类型的存储,并且每种类型的存储可以允许任意复杂的配置参数集,例如索引大小、持久性、事务行为、索引策略、安全性和 ACL 考虑等。
我同意@Fernando 的观点,也许更多的多态性可能更有意义,也许多态性与泛型和类型限制相结合可能是最好的,例如
public interface IFoo
{
bool Bar<T>(T parameters) where T : IBarConfig;
}
public interface IBarConfig
{
String ID { get; set; }
}
然后用这样的实现:
public class MyFoo
{
bool Bar<T>(T config) where T : MyBarConfig
{
//Implementation
}
}
public class MyBarConfig : IBarConfig
{
public String ID { get; set; }
public long IndexSegmentSize { get; set; }
//Etc...
}
这出乎我的意料,所以不确定在 MyFoo 中定义 Bar() 是否真的合法,其类型限制与其实现的接口不同?
【问题讨论】:
-
除非您受限于 .Net Framework 的早期版本,否则我将始终使用通用版本。除非您处理大量数据,否则可重用代码的优势远远超过性能损失
-
如果您需要知道您正在调用
IFoo的哪个 实现,以便决定传递Bar的参数类型,那么您可能使用了错误的抽象.IFoo的调用者应该与实现无关,但您的设计与此相反。您能否详细说明在更复杂的情况下需要传递什么样的参数?也许这些参数属于实现的属性,而不是方法的参数。 -
@Kirk Woll 为我的问题添加了更多细节