我有这个API函数:
public ResultEnum DoSomeAction(string a, string b, DateTime c, OtherEnum d,
string e, string f, out Guid code)
我不喜欢这个。因为参数顺序变得不必要地重要。添加新字段变得更加困难。很难看到正在传递的是什么。很难将方法重构为更小的部分,因为这会增加传递子函数中所有参数的额外开销。代码更难读。
我想出了最明显的想法:让一个对象封装数据并传递它,而不是一个接一个地传递每个参数。这是我想出来的:
public class DoSomeActionParameters
{
public string A;
public string B;
public DateTime C;
public OtherEnum D;
public string E;
public string F;
}
这将我的API声明简化为:
public ResultEnum DoSomeAction(DoSomeActionParameters parameters, out Guid code)
好的。看起来很简单,但我们实际上引入了一个巨大的变化:我们引入了可变性。因为我们之前所做的实际上是传递一个匿名的不可变对象:堆栈上的函数参数。现在我们创建了一个非常可变的新类。我们创建了操纵调用者的状态的功能。这太糟糕了。现在我希望我的对象是不可变的,我该怎么办?
public class DoSomeActionParameters
{
public string A { get; private set; }
public string B { get; private set; }
public DateTime C { get; private set; }
public OtherEnum D { get; private set; }
public string E { get; private set; }
public string F { get; private set; }
public DoSomeActionParameters(string a, string b, DateTime c, OtherEnum d,
string e, string f)
{
this.A = a;
this.B = b;
// ... tears erased the text here
}
}
正如您所看到的,我实际上重新创建了我的原始问题:参数太多。很明显,这不是我们应该走的路。我该怎么办呢?实现这种不变性的最后一种选择是使用“只读”结构,如下所示:
public struct DoSomeActionParameters
{
public readonly string A;
public readonly string B;
public readonly DateTime C;
public readonly OtherEnum D;
public readonly string E;
public readonly string F;
}
这使我们可以避免使用过多参数的构造函数,并实现不变性。实际上,它解决了所有问题(参数排序等)。然而:
每个人(包括exposing public fields are bad.
就在那时,我感到困惑,并决定写这个问题:在C#中,什么是在不引入易变性的情况下避免“太多参数”问题的最直接的方法?有没有可能使用只读结构来达到这个目的,而不是有一个糟糕的API设计呢?
CLARIFICATIONS:
,
更新
这里提供的答案有不同的优点/缺点。因此,我想把它转换成一个社区维基。我认为每一个带有代码样本和优点/缺点的答案都会成为未来类似问题的很好指南。我现在正在尝试找出如何做到这一点。
发布于 2011-06-04 21:12:52
框架中包含的一种风格通常类似于将相关参数分组到相关类中(但在可变性方面仍存在问题):
var request = new HttpWebRequest(a, b);
var service = new RestService(request, c, d, e);
var client = new RestClient(service, f, g);
var resource = client.RequestRestResource(); // O params after 3 objects
发布于 2011-06-04 21:59:07
使用构建器和特定于域的语言风格的API的组合--Fluent Interface。API有点冗长,但使用intellisense可以非常快速地输入内容,并且易于理解。
public class Param
{
public string A { get; private set; }
public string B { get; private set; }
public string C { get; private set; }
public class Builder
{
private string a;
private string b;
private string c;
public Builder WithA(string value)
{
a = value;
return this;
}
public Builder WithB(string value)
{
b = value;
return this;
}
public Builder WithC(string value)
{
c = value;
return this;
}
public Param Build()
{
return new Param { A = a, B = b, C = c };
}
}
DoSomeAction(new Param.Builder()
.WithA("a")
.WithB("b")
.WithC("c")
.Build());
发布于 2011-06-04 21:23:19
这里有一个非常明确的指示,这个类违反了Single Responsibility Principle,因为它有太多的依赖项。寻找将这些依赖项重构为Facade Dependencies集群的方法。
https://stackoverflow.com/questions/6239373
复制相似问题