现实世界中抽象类的使用简单示例

3

有没有一些关于使用抽象类的真实世界的简单示例呢?我正在尝试学习PHP的面向对象编程,但我仍然不明白 - 为什么应该使用抽象类以及何时使用(是的,我知道不可能创建抽象类的实例,只能创建继承它的类的实例)。

2个回答

1

也许您有一个图像类,并拥有2个驱动程序,即GD和ImageMagick。

您的基础类可能是

abstract class Image {

    public function resize($width, $height) {
        // Some prep code...
    }
}

那么你的GD驱动程序将会是这样的

class Image_Gd extends Image {
    public function resize($width, $height) {
        // Actual code
    } 
}

看看GitHub上的Kohana源代码。它有一个Image类,是抽象的

嗯,我以为创建 interface Image 并让 Image_Gd implements Image 就足够了? - Kirzilla
@Kirzilla 嗯,是的,你可以那样做。想象一下在基类中有代码。 - alex
最好不要查看Kohana的源代码。它并不是面向对象设计的最佳示例。 - Crozin
@Crozin 好的,那你有什么推荐呢? - alex

1

好的,假设你想要加载脚本配置。这个配置可以存储在数据库/XML/INI/YAML文件中。每个驱动程序都必须实现一些接口,我们称之为ConfigurationLoader

interface ConfigurationLoader {
    public function load();
    public function get($key, $default = null);
}

// The final usage of the code:

$configuration = new XMLConfiguration('./some/file.xml');
$configuration = new YAMLConfiguration('./some/file.yaml');
$configuration = new DatabaseConfiguration($dbHandler, 'table_name');

$configuration->load();
echo $configuration->get('abc.def.ghi');

现在我们需要实现我们的驱动程序。你应该注意到的第一件事是基于文件的驱动程序可能是相同的。唯一的区别是它们每个都以不同的方式解析文件源。另一方面,数据库驱动程序完全不同。

class DatabaseConfiguration implements ConfigurationLoader {
    protected $config = array();

    protected $pdo, $tableName;

    public function __construct(PDO $dbHandler, $tableName) {
        $this->pdo = $pdo;
        $this->tableName = $tableName;
    }

    public function load() {
        $this->config = /* fetch data from database */;
    }

    public function get($key, $default = null) {
        return array_key_exists($this->config, $key) ? $this->config[$key] : $default;
    }
}

现在我们需要实现XML、INI和YAML驱动程序。它们都几乎相同,因此... 让我们创建一些处理通用代码的抽象类:

 abstract class FileConfiguration implements ConfigurationLoader  {
      // Each file-based configuration loader has a constructor that takes file name as first argument
      protected $filename;

      public function __construct($filename) {
          $this->filename = $filename;
          $this->getFileContents();
      }

      // Each file-based driver has to store file content
      protected $fileContent;

      protected function getFileContents() {
          $this->fileContents = file_get_contents($this->filename);
      }

      // Each driver will have to implement its own implementation of load().
      // XMLConfiguration will parse XML, INIConfiguration will parse INI etc. 
      abstract public function load();

      // However all of them will store parsed configuration in $config array:
      protected $config = array();

      public function get($key, $default = null) {
          return array_key_exists($this->config, $key) ? $this->config[$key] : $default;
      }
 }

FileConfiguration 必须是抽象的,因为它不知道如何解析文件内容。只有交付的类才知道如何做到这一点:

 class XMLConfiguration extends FileConfiguration {
      public function load() {
          $xml = simplexml_load_string($this->fileContents);

          foreach ($xml->root as $config) {
              $this->config[(string) $config->key] = (string) $config->value;
          }
      }
 }

 class YAMLConfiguration extends FileConfiguration {
      public function load() {
          $yaml = new SomeYAMLParser($this->fileContents);

          foreach ($yaml->parse() as $config) {
              $this->config[$config['key']] = $config['value'];
          }
      }
 }

 class INIConfiguration extends FileConfiguration {
      public function load() {
          ...
      }
 }

如您所见,这个例子中可能会有一个更抽象的类AbstractConfiguration,它将存储$config属性和get($key, $default = null)方法,并且它将成为DatabaseConfigurationFileConfiguration的父类。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接