【问题标题】:Why can't we redefine in an implementing class the visibility of methods declared on an interface?为什么我们不能在实现类中重新定义接口上声明的方法的可见性?
【发布时间】:2019-07-14 00:04:30
【问题描述】:

根据我对接口的理解,它们是实现它们的所有类都必须遵守的构造计划。

如果我想创建几个数据库类,比如说一个类来管理 mySQL,另一个类来管理 PostgreSQL,我会创建一个接口,我将在其中放置我的站点工作所需的所有方法,以及我的两个类model.mysqlManager.phpmodel.postgresqlManager.php 将实现此接口。

我不明白的是为什么我们不能在我们的类中重新定义来自接口的方法的可见性。我知道它们是隐式公开的。

就我而言,我希望有这个界面:

interface.iDatabase.php

interface iDatabase {
    public function connectDatabase();
    // other functions
}

还有这些课程:

model.mysqlManager.php

class mysqlManager implements iDatabase {

    protected $db;

    const HOST = '127.0.0.1';
    const DBNAME = 'dbname';
    const CHARSET = 'utf8';
    const USERNAME = 'username';
    const PASSWORD = 'password';


    protected function connectDatabase() {
        if(!isset($this->db)) {
            try {
                $this->db = new PDO('mysql:host='.self::HOST.'; dbname='.self::DBNAME.'; charset='.self::CHARSET.'', self::USERNAME, self::PASSWORD);
            } catch(Exception $e) {
                die('Erreur : '.$e->getMessage());
            }
        }

        return $this->db;
    }
}

model.postgresqlManager.php

<?php

class postgresqlManager implements iDatabase {

    protected $db;

    const HOST = '127.0.0.1';
    const DBNAME = 'dbname';
    const CHARSET = 'utf8';
    const USERNAME = 'username';
    const PASSWORD = 'password';

    protected function connectDatabase() {
        //function code
    }
}

我不想从我的类之外访问这个方法,但我希望所有数据库类都实现它。

我的问题是:

  1. 接口如何影响实现它的类?它不只是用来定义必须拥有的方法吗?
  2. 我还可以使用什么其他方式来强制我的类实现此方法?

【问题讨论】:

  • All methods declared in an interface must be public; this is the nature of an interface. - secure.php.net/manual/en/language.oop5.interfaces.php
  • 使用抽象类。我们称它为 AbstractDatabase 并将方法 connectDatabase 声明为抽象。根据你想要做什么,你可以让你的抽象类实现接口和 postgresqlManager,mysqlManager 都扩展抽象类 AbstractDatabase

标签: php oop interface


【解决方案1】:

接口如何影响实现它的类?它不只是用来定义必须拥有的方法吗?

接口定义了实现类必须遵守的契约。

它必然定义了一个public接口。为了让这个契约对其他类有用,接口上定义的方法必须是公共的。私有/受保护的方法不是契约的一部分,而是内部实现的一部分,逻辑上不是接口的一部分。无论A 类有什么私有/受保护方法,B 类都不感兴趣,因为它们无论如何都不能使用。

如果一个类可以改变在接口中声明的方法的可见性,那么它将不符合约定

我可以用什么其他方式来强制我的类实现这个方法?

一种常见的模式是具有可用于满足接口要求的特征。显然,trait 提供的方法也必须是公开的。


如果你想定义一个类族的内部结构,接口不是你应该寻找的语言特性,而是继承。您可以在父类中完全或部分定义方法,并在子类中使用这些方法。

请注意,继承和接口是非常不同的动物,适用于非常不同的目的,并且继承会带来一些权衡,例如增加接口所没有的耦合。

但如果你想这样做,你可以创建类似的东西:

abstract class AbstractDatabase {
    protected abstract function connectDatabase();
}

class mysqlManager extends AbstractDatabase {
    protected function connectDatabase() {
       // do your thing
    }
}

通过声明类abstract,它不能被直接实例化,而必须被扩展。通过将方法声明为protected abstract,您的意思是继承类必须实现该方法才能工作。

【讨论】:

  • 我不明白为什么我们不能只在接口中声明强制函数,然后在具有所需可见性的类中实现它们。根据我从您的解释中了解到的情况,能够重新定义类中函数的可见性将允许在多个类中实现不同的实现,因此不再尊重保证在任何地方都实现相同的约定。对吗?
  • 我现在明白了为什么抽象类更适合我的情况,但是在这种情况下接口会更有用,因为它的所有功能都是公共的?在这种情况下,我们是否可以创建一个仅使用受保护方法继承的抽象类,并创建一个我们将实现的接口来定义所有获取数据的函数?感谢您的宝贵帮助!
  • 接口定义了其他类如何使用(“接口”)一个类。根据定义,私有方法不能成为该合同的一部分,因为其他类不关心内部实现细节,它们只关心某些方法是否具有特定签名。每当你想定义一个类应该如何被其他类使用时,接口都是有用的。
  • 考虑一个假设的 Pen 界面:它可以定义为“如果您将尖端按到平坦、无光泽的表面上,它就会书写”。作为班级的用户,您不关心笔如何将墨水从墨水库移动到尖端您甚至可能不关心它是墨水还是任何其他物质。这些是私有方法和属性。您只关心它是否满足“通过推动尖端写入”界面。如果“推尖写”方法变为私有,那么它就不再是笔了,因为该类的用户不能写。
  • 好的!正如我在其他地方所读到的,该接口实际上就像一个 API。接口的目的是列出可以使用的方法,而不必担心它们的实现,因为无论我们选择获取结果的方式(在我们的例子中是 mysql 或 postresql ),这些方法都会给出相同的结果。从使用接口(或 API)的用户的角度来看,比创建类的开发人员更容易理解。谢谢你的一切!
【解决方案2】:

我的问题是:

接口如何影响实现它的类?才不是 它仅用于定义必须具有的方法?什么 我可以使用其他方式来强制我的类实现此方法吗?

接口只定义公共方法。实现您想要的另一种方法是使用抽象 connectDatabase 方法而不是接口定义一个 abstract 类。然后用你的实现扩展那个抽象类。

抽象方法必须在子类中实现,所以这对你来说就像一个接口契约。

【讨论】:

    猜你喜欢
    • 2013-01-27
    • 2011-02-25
    • 1970-01-01
    • 2010-09-06
    • 2015-09-05
    • 2017-09-13
    • 2023-03-13
    • 1970-01-01
    相关资源
    最近更新 更多