基于接口的设计和可选的方法参数

时间:2012-05-09 15:47:21

标签: c# .net design-patterns interface

我正在为新的Web API创建一个C#包装器库。

该服务提供了一组API,其中每个方法接收几个必需参数,以及一些可选参数(每个方法可能接收不同的强制/可选参数)。

参数以POST方式发送,作为长串的param = value& param2 = value2& ....

习惯了基于界面的设计 - 在这种情况下是否适合?

我找不到一个很好的解决方案,可以将所有API方法和参数映射到单个界面中,而不会产生方法重载,造成大麻烦,这会让用户更难以使用。

它的外观示例:

public interface IServiceAPI
{
    void MethodA(string mandatory, string mandatory2);
    void MethodA(string mandatory, string mandatory2, int optional);
    void MethodB(string mandatory);

    ... etc
}
  • 我知道.NET 4中引入的可选参数。这不是一个好的解决方案,因为这个库是针对较低版本的.NET,也是因为“可选参数”实际上只是一种设置默认值的方法值,而不是NOT SENDING参数的任何值。

基于接口的设计是否适合这里?或换句话说 - 基于界面的设计最适合哪里?

5 个答案:

答案 0 :(得分:2)

首先,我不认为设计具有大量重载的接口是个好主意。除非函数执行某些不同的,否则如果他们想要输入一些默认值,则应该将其留给使用该界面的人。

那就是说,其次你正在写的实体似乎会更好地为你提供基类。 ServiceAPI这个名称有助于暗示至少一些标准功能。通过这种方式,您可以拥有多个重载,并让任何子类覆盖主方法。

答案 1 :(得分:1)

接口是正确的方法,但我认为你使用的是错误的接口。我将创建一个IOptionalParameter接口,如下所示:

interface IOptionalParameter<T>
{
    public bool IsSet {get;}
    public T Value {get;}
}

然后,您可以在API中公开一个方法,每个参数的类型为IOptionalParameter。

这也将使您用于构建url请求字符串的代码更整洁。如果它有意义,你可以在界面中添加一个Name属性,从而进一步简化它。

<强>更新

总结三种不同的方法以及它们之间的权衡:

  1. 超载 - 更清楚的是参数是可选的,但会导致混淆实施中的潜在差异并使实施变得有点混乱
  2. Nullable类型 - 不太清楚参数是可选的,但在实现方面更清晰
  3. IOptionalParameter - 明确说明参数是否可选,实现是干净的,但从客户端调用可怕

答案 2 :(得分:1)

您的方法似乎有多个参数。根据我的经验,3个参数应该是最大的。要解决这个问题(并且作为副作用找到可选/必需参数的解决方案),我建议将参数打包到类中:

class MethodAParameters
{
    public string Required1 {get;set;} //add validation in setter (nulls are not allowed)
    public string Required2 {get;set;} //add validation in setter (nulls are not allowed)
    public int? Optional1 {get;set;} //nulls allowed

    public MethodAParameters(string required1, string required2)
    {
        Required1 = required1;
        Required2 = required2;
    }
}

如您所见,这样的设计强制传递所需的参数(您无法在不指定参数的情况下创建参数实例)并允许添加可选参数。 当然,如果某些方法共享相同的参数子集,那么您应该继承参数类。

如果空值也相关,则前面提到的IOptionalParameter似乎是必要的(与此参数类方法结合使用)。

请注意,您的代码应为SOLID。当我看到您提供的示例时,我会关注单一责任原则。当然,如果不知道我只是猜测的实际代码,那么请将其视为一条建议。

答案 3 :(得分:0)

可以为空的数据类型?

例如,而不是

void MethodA(string mandatory, string mandatory2);
void MethodA(string mandatory, string mandatory2, int optional);

您可以将其简化为

void MethodA(string mandatory, string mandatory2, int? optional);

但是,如果可选参数是引用类型,那么对于调用者来说,它们可能不会向它传递null。

如果你有很多可选参数,例如v oid MethodC(string mandatory, string mandatory2, string optional1, int? optional1, string optional2);,你不想为所有可能的组合提供签名,你可以简单地提供:

MethodC(string mandatory, string mandatory2) // for people that just want the basic functionality
MethodC(string mandatory, string mandatory2, string optional1, int? optional1, string optional2); // for people that want to specify extra, and they can pass null for some of the optional ones if they like.

答案 4 :(得分:0)

我不确定为什么你想要一个接口而不是常规类。其他类是否会实现此接口,或者您只是在寻找访问API的标准方法?

如果您只是在寻找访问API的标准方法,我建议对构建器模式进行修改。构建器模式通常用于类,但我不明白为什么它也不能用于方法。有关基于类的示例,请参阅http://cdmckay.org/blog/2009/07/03/joshua-blochs-builder-pattern-in-csharp/

这是我对你提供的东西的尝试。如果有语法错误,我很抱歉,我家里的编辑有点缺乏......

public class AccessServiceAPI
{
    private void MethodA(string mandatory, string mandatory2, string optional)
    {
        // do stuff
    }

    public class MethodABuilder
    {
        private string Mandatory { get; set; }
        private string Mandatory2 { get; set; }
        private string Optional { get; set; }

        public MethodABuilder( string mandatory, string mandatory2)
        {
            Mandatory = mandatory;
            Mandatory2 = mandatory;
            Optional = "default value";
        }

        public MethodABuilder Optional( string optional )
        {
            Optional = optional;
            return this;
        }

        public void Build()
        {
            MethodA(mandatory, mandatory2, optional);
        }
    }
}

然后客户端会调用这样的方法:

MethodABuilder.Builder(mandatory, mandatory2).Optional(optional).Build();

如果他们不想为可选参数设置值,他们可以跳过它。