PHP 设计模式 - 继承与适配器模式


PHP design patterns - inheritance vs adapter pattern?

我对适配器模式的概念有点困惑。我发现适配器类与我通常编写的扩展类非常相似。那么,它们之间实际上有什么区别呢?

例如(此链接中的示例),

简单书.php,

class SimpleBook {

    private $author;
    private $title;

    function __construct($author_in, $title_in) {
      $this->author = $author_in;
      $this->title  = $title_in;
    }

    function getAuthor() {return $this->author;}

    function getTitle() {return $this->title;}

  }

书籍适配器.php

include_once('SimpleBook.php');
  class BookAdapter {

    private $book;

    function __construct(SimpleBook $book_in) {
      $this->book = $book_in;
    }

    function getAuthorAndTitle() {
      return $this->book->getTitle() . ' by ' . $this->book->getAuthor();
    }

  }

图书扩展.php,

include_once('SimpleBook.php');
      class BookExtension extends SimpleBook{
        function getAuthorAndTitle() {
          return $this->getTitle() . ' by ' . $this->getAuthor();
        }

      }

第二种解决方案似乎要简单得多。那么它(以及一般的其他继承类)是否被视为适配器类呢?

区别在于如何将类与多态性一起使用。

如果使用继承,任何需要SimpleBook的函数也将接受BookExtension,或任何其他扩展SimpleBook的类。例如,如果您有:

function PigLatinTitle(SimpleBook $b) {
    return PigLatin($b->getTitle());
}

可以在BookExtension上调用此函数,因为它继承了 SimpleBook::getTitle() 方法。

请注意,它不能反过来工作:期望BookExtension的函数不适用于SimpleBook。例如,如果函数调用 getAuthorAndTitle() ,如果参数是SimpleBook,则会失败,因为那里没有这样的方法。

如果使用适配器,则这两个类是独立的。期望SimpleBook的函数不接受BookAdapter,反之亦然。你不能在BookAdapter上调用PigLatinTitle(),因为没有BookAdapter::getTitle()方法。

您可以通过向 BookAdapter 添加一个__call()魔术方法,然后在 $this->book 上重新调用该方法,使适配器像继承一样工作:

public function __call($name, $arguments) {
    return call_user_func_array(array($this->book, $name), $arguments);
}

您可以阅读有关适配器的有趣问题。它很可能是具有内部和外部类的包装器模式:代理、装饰器、适配器和桥接模式有何不同?