1

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

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

参数在 POST 方法中发送,作为一个长字符串 param=value¶m2=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,而且因为“可选参数”实际上只是一种设置默认值的方法,并且不是为了不发送参数的任何值。

基于接口的设计可能适合这里吗?或者换一种说法——基于界面的设计最适合哪里?

4

5 回答 5

2

首先,我不认为设计一个有很多重载的接口是一个好主意。除非函数做一些不同的事情,否则你应该把它留给使用接口的人,如果他们想输入一些默认值。

也就是说,其次,您正在编写的实体似乎可以更好地作为基类为您服务。ServiceAPI 这个名字至少暗示了一些标准功能。通过这种方式,您可以拥有多个重载,并让任何子类覆盖主要方法。

于 2012-05-09T15:55:54.483 回答
1

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

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

然后你可以在你的 API 中只公开一个方法,每个参数都是 IOptionalParameter 类型。

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

更新

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

  1. 重载 - 参数是可选的更清楚,但会导致实现中的潜在差异混淆并使实现有点混乱
  2. 可空类型 - 不是很清楚参数是可选的,但在实现方面更清晰
  3. IOptionalParameter - 明确声明参数是否可选,实现很干净,但从客户端调用很糟糕
于 2012-05-09T16:00:33.843 回答
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。当我查看您提供的示例时,我担心单一责任原则。当然,在不知道实际代码的情况下,我只是在猜测,所以将其视为一条建议。

于 2012-05-12T00:37:11.837 回答
0

可空数据类型?

例如,而不是

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

您可以将其简化为

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

但是,如果可选参数是引用类型,那么调用者可能不会那么明显地知道他们可以将 null 传递给它。

如果您有很多可选参数,例如 void 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.
于 2012-05-09T15:56:20.520 回答
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();

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

于 2012-06-08T05:05:29.443 回答