【问题标题】:constructor methods in interfaces接口中的构造方法
【发布时间】:2009-04-23 18:52:02
【问题描述】:

接口中的构造方法不好吗?

【问题讨论】:

  • 既然你不能实例化一个接口你怎么用它呢?
  • 我的意思是在接口中指定构造函数。
  • 删除了主观标签。这个问题似乎没有任何主观性。
  • 这个问题没有用语言标记。语言的选择可能会影响这个问题的答案。
  • 添加了 PHP 标签。支持接口中的构造函数。用例:需要会话对象才能工作的用户对象。接口中的构造函数告诉程序:如果你想创建我,你需要使用会话对象作为构造函数参数来构造我。

标签: php oop


【解决方案1】:

为什么人们认为任何人都想实例化接口?

我们要做的是强制实现者实现构造函数,就像其他接口方法一样。

接口就像合同。假设我有一个接口 Queue,并且我想确保实现者使用一个参数创建一个构造函数,该参数创建一个单例队列(一个仅包含该元素的新队列)。为什么这不应该是合同的一部分?至少有 Java 接口,不能指定。

【讨论】:

  • +1 所以,不,它们还不错。 Why do people think that anybody wants to instantiate the interface? 同意,IMO OP 并没有这么问。如果一个类在每次实例化时都需要一个值(例如,一个包装类),那么在我看来,数据传递契约可能很有用。特别是在 PHP 中,方法不能被覆盖 - 构造函数被“锁定”到某种行为。
  • 方法可以在 PHP 中被覆盖,但不能被重载。
  • 也许@Steve 指的是匹配构造函数签名的义务。
  • 如果你想任意强制一个接口的实现来指定 n 个构造函数参数,你做错了 OOP。在静态方法的情况下,您永远不会有一个对象来解析类型,即多态性不适用于静态方法。构造函数是静态方法。 Queue 类型的客户端可能想要调用addget。但是,这些客户端永远不会调用构造函数,因此这些接口不应指定构造函数方法。能够在接口中指定 __construct 是 PHP 是如何被创建而不是设计的一个很好的例子。
【解决方案2】:

它们很糟糕,因为它们没有任何用途。从本质上讲,接口只是一个数据传递合约。没有附加接口的实现,因此不需要初始化,也不需要构造函数。

如果您需要某种初始化,最好使用抽象类。

【讨论】:

  • 顺便说一句,我认为接口不仅仅是“简单的数据传递合同”。它应该被认为是责任合同,而责任合同又包括签名规范。
  • @isntn,接口的核心是指定如何传递数据。唯一认为保证行为的是合约和测试框架。接口可以暗示行为,但不能保证它
  • 我同意 JaredPar。如果您的接口中有构造函数,那么您似乎需要一个抽象类。您将获得实现此接口的组件的一些常见行为,至少对于与传递给 __construct 方法的变量相关的 setter/getter 方法,因此您应该去,IMO,在这种情况下使用抽象类。
  • 使用抽象类的解决方案取决于上下文 - 您是否想要(或可以)限制实现者,以便他们必须从特定类继承。 PHP 是一种单继承语言,因此在某些情况下这种限制可能会或可能不会被接受。
【解决方案3】:

首先,我不同意接口只是一个数据传递合同。如果这是真的,您将被允许在接口中定义属性。

我并不认为这样做很奇怪:

interface IDBConnection
{
    function __construct( $connectionString );
    function executeNonQuery( $commandText, $paramters=null);
    function executeScalar( $commandText, $paramters=null);
    function executeSingle( $commandText, $paramters=null);
    function executeArray( $commandText, $paramters=null);
}

这将使您能够基于简单的反射创建第三方类的实例以进行数据访问,而不仅仅是作为数据契约。

我很确定这不是最好的例子,我会在现实世界中选择一个抽象基类,但我也很确定定义构造函数方法有完全正当的理由' 在一个我没想到的界面中签订合同。

我还没有看到它完成,但我不认为这很奇怪或不好。

【讨论】:

    【解决方案4】:

    虽然接口在大多数语言中不能有构造函数,但Factory pattern 提供了构造对象的契约,类似于接口。看看那个。

    【讨论】:

      【解决方案5】:

      无论它们是否不好,我不知道有任何语言能够在接口上指定构造函数。

      话虽如此,我个人并不认为对象的构造函数是该对象接口的一部分,因此向接口添加构造函数会抑制接口提供的自然灵活性。

      【讨论】:

      • 来晚了,但是PHP有这个能力。 (这并不能使它成为一个值得拥有的功能,但这只是我的看法。)
      【解决方案6】:

      您有时必须通过需要参数的构造函数来实例化不可变的多态对象,并且您可能在接口中需要该构造函数,原因与您可能需要接口中的其他公共方法完全相同,例如......

      假设您必须实例化一个多态对象,它的类实现您的接口并由客户端代码提供。作为一个愚蠢但简单的场景,假设这个对象是一个值对象,因此应该是不可变的,这意味着对象的状态从实例化的那一刻起就应该是有效的......

      $immutablePolymorphe = $userConfig['immutable_polymorphe_class'];
      $immutablePolymorphe = new $immutablePolymorphe($state);
      // Then do something with that polymorphe...
      

      那么,如果你没有在接口中定义带有参数的构造函数呢?因此,我相信接口中的构造函数可以与接口中的任何其他公共方法一样合法的原因......

      【讨论】:

        【解决方案7】:

        我不知道 Google 为什么把我派到这里 :)

        但这个问题很有趣,我在很多项目中看到有人在接口中定义了构造函数。但我真的认为这是一个无用的限制。该类的任何客户端都不能调用__construct

        并且在接口中定义它并不会限制任何行为,我仍然可以随心所欲地实现它,我什至可以有一个空函数,例如:

        ...
        function __construct(string $name) {}
        ...
        

        那有什么好处呢?它只是阻止你做多态性,没有任何好处。

        如果你有:

        <?php
        interface Shape {
           function __construct(int $width, int $height);
           public function getArea();
        }
        
        class Square implements Shape {
           public function __construct(int $width, int $height) {...}
           public function getArea(){...}
        }
        
        // This will throw an exception because it does not implement the correct constructor signature!
        class Circle implements Shape {
           public function __construct($radius) {...}
           public function getArea(){...}
        }
        

        即使你想扩展 Square,你也必须实现相同的构造函数!。

        答案中有一个例子:

        你必须实例化不可变的多态对象...

        示例如下:

        $immutablePolymorphe = $userConfig['immutable_polymorphe_class'];
        $immutablePolymorphe = new $immutablePolymorphe($state);
        // Then do something with that polymorphe...
        

        这是聪明的想法,但前提是您可以将$userConfig 数组中的字符串限制为特定接口!至少据我所知这是不可能的。

        所以底线 :D 我认为在界面中使用 __construct 是不好的,它会阻止您改进软件,它会鼓励您使用不好的解决方法。

        【讨论】:

          猜你喜欢
          • 2023-03-06
          • 1970-01-01
          • 2019-03-03
          • 1970-01-01
          • 1970-01-01
          • 2012-10-14
          • 2011-02-17
          • 2010-12-13
          • 1970-01-01
          相关资源
          最近更新 更多