【问题标题】:Writing methods in interface with specific or variadic arguments?在具有特定或可变参数的接口中编写方法?
【发布时间】:2019-12-11 02:05:45
【问题描述】:

我正在编写与第 3 方 API 网关的集成,并且为了使其尽可能解耦(并且能够在将来更改提供程序),我创建了 3 个接口,其中包含用于从网关读取、写入和删除(因为我需要使用很多方法,所以我不想把所有东西都塞进一个大接口中,违反接口隔离原则)。 API Gateway 用于处理应用创建和其他 CRUD 操作。

而且我不确定前进的最佳方式是什么。我可以创建这样的界面

interface Api_Gateway_Create {
  public function create_app( string $organization, string $developer_id, string $body );

  // other methods.
}

然后,在做具体实现的时候,我会创建一个实现这个的类,当我需要使用它的时候,我需要提供三个参数。

这似乎有点束缚。如果更换提供程序时不再需要$developer_id 怎么办?我可以为所有参数设置一些默认值

interface Api_Gateway_Create {
  public function create_app( string $organization, 
           string $developer_id = 'some-default-value', 
           string $body = 'some-default-value' );

  // other methods.
}

但这意味着我最终会得到我可能不需要的参数,这可能会打乱我的实现。

最后想到的是我可以放一个可变参数,然后让实现处理参数

interface Api_Gateway_Create {
  public function create_app( ...$arguments_list );

  // other methods.
}

在我的实现中

class Create_App_Implementation1 implements Api_Gateway_Create {
  public function create_app( ...$arguments_list ) {
    list( $organization, $developer_id, $body ) = $arguments;
    // Some business logic.
  }
}

class Create_App_Implementation2 implements Api_Gateway_Create {
  public function create_app( ...$arguments_list ) {
    list( $organization, $app_key, $body ) = $arguments;
    // Some business logic.
  }
}

这样我就不需要关心我的提供者是否提供这些参数,因为我只会实现我需要的那些。

然而,这带来了另一个问题。在消费代码中,比如说一个将通过依赖注入使用create_app() 方法的类,我需要特别注意传递正确的值。这不是未来的证明,因为我还需要更改消费类中的代码(在我看来,这与接口的意图相反)。

使用第一个,我将永远不必更改使用代码,因为如果我期望相同的结果(基于相同的输入参数),我不在乎我正在使用哪个提供程序。但正如我已经提到的,这似乎有点限制。两个提供商可能有不同的处理方式。

是否有人不得不面对这种事情?处理这种事情的行业标准是什么

我正在使用 PHP 编写代码,但我认为 Java 也可能适合它,因为它具有面向对象的特性。

【问题讨论】:

    标签: java php interface implementation


    【解决方案1】:

    是否有人不得不面对这种事情?处理这种事情的行业标准是什么?

    1. 我相信他们有。
    2. 没有“行业标准”的方式来做到这一点。

    (您可能应该从词汇表中删除诸如“行业标准”和“最佳实践”之类的短语。在我看来,它们不利于沟通。阅读 "No best practices" 并思考他在说什么。)


    我对 PHP 不够熟悉,无法说出用那种语言解决这个问题的常用方法。


    在Java中,有两种常用的方法:

    1. 为常见情况定义许多不同的方法(或构造函数)重载;例如

          public interface CreateAppApi {
              public String create_app(String organization, String developerId, 
                                       String body);
              public String create_app(String organization, String developerId);
              public String create_app(String developerId);
          }
      

      如果参数都具有相同的类型,这将无法正常工作:不同的重载可能无法区分。

    2. 使用流畅的构建器模式;例如像这样定义接口:

          public interface CreateAppRequest {
              public CreateAppRequest organization(String value);
              public CreateAppRequest developer(String developerId);
              public CreateAppRequest body(String body);
              public String send();
          }
      

      并像这样使用它:

          String result = new CreateAppRequestImpl().organization(myOrg)
                                .developer(myId).body(someBody).send();
      

      从 API 用户的角度来看,这很有效,而且很容易发展。 (只需添加更多用于向 API 提供新参数的方法并实现它们。)缺点是样板代码更多。

    Java 支持可变参数,但它们不适合您描述的用例。 (这适用于您有可变数量的值本质上意味着相同事物的情况;例如,表示我们假设的“应用程序”的方法的字符串的内联列表。)


    在 Python 中,没有方法重载……因为不需要它。反而: - 您可以使用位置或关键字参数,或它们的组合。 - 你也有像 *args**kwargs 这样的构造来传递任意参数而不显式声明它们。

    一般来说,关键字参数更适合需要具有不同含义和(可能)类型的各种参数的 API。

    所以在这个例子中你可能会这样写:

    class CreateAppRequest(SomeBaseClass):
    
        def __init__(self, organization='defaultOrg', developer=None, body='',
                     **kwargs):
            super(self, CreateAppRequest).__init__(**kwargs)
            if developer is None:
                raise Exception('developer is mandatory')
            self.developer = developer
            self.organization = organization
            self.body = body
    
        def send(self):
            ...
    

    builder/fluent 方法也可以在 Python 中使用。

    【讨论】:

    • 据我所知,我认为 PHP 中没有像 Java 中描述的方法重载。但是构建器模式看起来很有希望。我可以尝试定义可以在实现中使用的某些 getter。将不得不考虑它。另外,感谢有关最佳实践的链接,我已经阅读了第一部分,看起来很有趣:)
    • 我明确表示我不是在谈论 PHP。你用 Java 标记了这个问题,我从这个角度回答。
    • 是的,我明白了,只是说我不确定是否会超载。我可以阅读 Java 代码(Java 技能为 0),但它们的行为确实不同,我完全理解:D
    猜你喜欢
    • 2017-07-08
    • 2018-10-09
    • 1970-01-01
    • 2016-03-05
    • 2021-08-22
    • 2011-09-01
    • 2012-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多