【问题标题】:Understanding Interfaces and Abstract Classes理解接口和抽象类
【发布时间】:2014-10-01 00:40:45
【问题描述】:

我从未在 PHP 中使用过接口或抽象类,但我想支持相同对象的相似但不同类型的对象(在本例中为网络交换机),并可能在未来添加更多。我通过 SSH (PHPSecLib) 与他们通信,交互方式不同,实际方法相同。

在我的特殊情况下,我相信一个抽象类,实现常量、私有变量、连接函数和构造函数/析构函数是合适的,只留下扩展类来实现功能,其中接口只是一个模板,但每个扩展类仍然会重新实现它们之间相同的方法。

我认为抽象类是在这种情况下要走的路是正确的吗?是否需要将空方法放置在被扩展类覆盖的抽象类中,或者扩展类是否可以包含抽象类中不存在的方法?

例子:

<?php

    set_include_path(get_include_path() . PATH_SEPARATOR . '/home/devicepo/public_html/include/PHPSecLib');

    include('Net/SSH2.php');
    include('File/ANSI.php');

    abstract class Switch
    {
        const STATUS_UNKNOWN = "-1";
        const STATUS_OFFLINE = "0";
        const STATUS_ONLINE = "1";

        public $conn;

        private $_server;
        private $_username;
        private $_password;

        private $_bashshell;

        public function __construct($server, $username, $password)
        {
            if (!$server)
                die("Switch configuration not Defined");

            $this->_server = $server;
            $this->_username = $username;
            $this->_password = $password;
        }

        public function connect()
        {
            // Establish new SSH2 Connection
            $this->conn = new Net_SSH2($this->_server, 22);

            if(!$this->conn->login($this->_username, $this->_password))
            {
                die("Failed to connect to Switch: " . $this->_server);
            }
        }

        public function enable_port($port)
        {
            // Define in extended classes
        }

        public function disable_port($port)
        {
            // Define in extended classes
        }
    }

?>

【问题讨论】:

    标签: php oop interface abstract-class phpseclib


    【解决方案1】:

    我相信在你的情况下 Abstract 类是要走的路。原因是:

    1. 您的子类与父类共享大部分代码

    2. 您的子类具有相似性的概念。

    关于第 2 点更具体,请记住实现相同接口的两个类不一定相关。界面代表一种能力。例如,考虑一架飞机和一只鸟。两者都可以实现可飞行的接口,但除此之外它们没有任何其他关系。另一方面,您的子类具有相似的类型。它们都是开关。所以你的抽象类可能是

    abstract class BasicSwitch { // You cannot use the name switch
    
        const STATUS_UNKNOWN = "-1";
    
        const STATUS_OFFLINE = "0";
    
        const STATUS_ONLINE = "1";
    
        public $conn;
    
        private $_server;
    
        private $_username;
    
        private $_password;
    
        private $_bashshell;
    
        public function __construct($server, $username, $password) {
    
            if (!$server) die("Switch configuration not Defined");
    
            $this->_server = $server;
    
            $this->_username = $username;
    
            $this->_password = $password;
        }
    
        public function connect() {
    
            // Establish new SSH2 Connection
    
            $this->conn = new Net_SSH2($this->_server, 22);
    
            if(!$this->conn->login($this->_username, $this->_password)) {
    
                die("Failed to connect to Switch: " . $this->_server);
            }
        }
    
        abstract public function enable_port($port);
    
        abstract public function disable_port($port);
    }
    

    具体的实现可以是

    class CiscoSwitch extends BasicSwitch {
    
        public function __construct($server, $username, $password) {
    
            parent::__construct($server, $username, $password);
        }
    
        public function enable_port($port) {
    
            echo 'Port is enabled';
        }
    
        public function disable_port($port) {
    
            echo 'Port is disabled';
        }               
    }
    

    这里要记住的最重要的一点是,CiscoSwitch 也是 BasicSwitch 的一种。这意味着 CiscoSwitch 可以在任何需要 BasicSwitch 的地方使用。因此,请考虑您有一个带有许多交换机的机架,并且您希望在机架中的所有交换机上启用相同的端口。这是你的 Rack 类:

    class Rack {
    
        protected $switches;
    
        public function addSwitch(BasicSwitch $switch) {
    
            $this->switches[] = $switch;
        }
    
        public function enable_ports($port) {
    
            foreach($this->switches as $switch) {
    
                $switch->enable_port($port);
            }
        }
    }
    

    如果您在抽象类 (BasicSwitch) 上而不是在实现上键入提示,您可以确定机架内的任何交换机都可以启用和禁用其端口。你真的不在乎它是哪个开关。你只知道它可以完成这项工作。 这就是接口上的代码而不是实现上的代码。这样,您的代码对扩展开放但对修改关闭。您可以根据需要创建任意数量的开关类型,但您将确保 Rack 类将继续工作。

    【讨论】:

      猜你喜欢
      • 2017-02-19
      • 2014-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-06
      • 2016-09-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多