Путаница в отношении шаблона адаптера и наследования (PHP)

У меня есть некоторая путаница с шаблоном адаптера, и мне интересно, является ли это правильный инструмент для того, что я пытаюсь достичь.

По сути, я пытаюсь добиться того, чтобы класс, написанный другим разработчиком, соответствовал написанному мною интерфейсу, сохраняя при этом другие методы этого класса.

Итак, я написал следующий интерфейс для объекта контейнера:

interface MyContainerInterface
{
public function has($key);
public function get($key);
public function add($key, $value);
public function remove($key);
}

Я также написал адаптер, который реализует этот интерфейс:

class OtherContainerAdapter implements MyContainerInterface
{
protected $container;
public function __construct(ContainerInteface $container) {
$this->container = $container;
}

public function has($key) {
$this->container->isRegistered($key);
}

...
}

И я использую это в моем классе следующим образом:

class MyClass implements \ArrayAccess
{
protected $container;
public function __construct(MyContainerInterface $container) {
$this->setContainer($container);
}

public function offsetExists($key) {
$this->container->has($key);
}

...
}

Тогда мое приложение использует класс так:

$myClass = new MyClass(new OtherContainerAdapter(new OtherContainer));

У меня проблема в том, что для того, чтобы использовать методы из адаптера, я должен написать следующее:

$myClass->getContainer()->getContainer()->has('some_key');

Когда в идеале это будет просто:

$myClass->getContainer()->has('some_key');

1

Решение

$myClass->getContainer()

должен вернуть экземпляр MyContainerInterface и это имеет has() функция. Это не должно иметь getContainer() функция.

2

Другие решения

Я не думаю, что вам нужен шаблон адаптера для этого. Мне кажется, что вы ищете полиморфное решение, которое может быть достигнуто простым использованием абстрактного класса. Адаптер не нужен.

Интерфейс

interface MyContainerInterface
{
public function has($key);
public function get($key);
public function add($key, $value);
public function remove($key);
}

Тогда абстрактный базовый класс:

class MyContainerBaseClass implements MyContainerInterface, \ArrayAccess
{
public function offsetExists($key) {
$this->has($key);
}
...
}

Затем подкласс от другого разработчика:

class ClassByOtherDeveloper extends MyContainerBaseClass
{
public function has($key) {
$this->isRegistered($key);
}

//you also need to implement get(), add(), and remove() since they are still abstract.
...
}

Вы можете использовать его в своем приложении следующим образом:

$object = new ClassByOtherDeveloper();
$x = $object->has('some_key');

Я предполагаю isRegistered Метод живет в реализации от другого разработчика.

Чтобы сделать его по-настоящему полиморфным, вам не нужно было бы жестко кодировать имя класса, но вы бы использовали переменную, которая может быть получена из файла конфигурации, базы данных или фабрики.

Например:

$className = "ClassByOtherDeveloper"; //this could be read from a database or some other dynamic source
$object = new $className();
$x = $object->has('some_key');
1