классы-обертки и внедрение зависимостей

Как все знают, суть классов-оболочек заключается в том, что они инкапсулируют функциональность другого класса или компонента. Вот простой класс, который обертывает небольшую часть библиотеки PHP Predis:

class CacheWrapper {

private  $client;

public function __construct(){

$this->client = new Predis\Client();

}

public function set($key, $value){

$this->client->set($key, $value);

}

public function get($key){

return $this->client->get($key);

}

}

и вот простой код, который использует этот класс-оболочку:

$client = new CacheWrapper();
echo $client->get('key1');

Когда этот класс прекрасно работает, проблема заключается в том, что он создает зависимость внутри класса, которую я хочу избежать, внедряя зависимость в класс, а не позволяя классу создавать свою зависимость, и поэтому класс-оболочка будет выглядеть так:

    class CacheWrapper {

private  $client;

public function __construct(Predis\Client $predisObj){

$this->client = $predisObj;

}

public function set($key, $value){

$this->client->set($key, $value);

}

public function get($key){

return $this->client->get($key);

}

}

поэтому я должен написать следующий код для использования класса оболочки:

    $predis = new Predis\Client();
$client = new CacheWrapper($predis);
echo $client->get('key1');

Но я думаю, что нет смысла использовать класс-обертку, так как я все еще использую исходный класс в своем коде. Итак, мой вопрос: концепции внедрения зависимостей и классов-оболочек противоречат друг другу и не могут быть использованы вместе, и каков наилучший способ решить проблему?

2

Решение

Как все знают, суть классов-оболочек заключает в себе
функциональность другого класса или компонента

Это не совсем точно. «Классы Wrapper» не так просты, как вы намекаете. Существует множество шаблонов дизайна, которые «оборачивают» класс.

Шаблон Adapter «оборачивает» объект, когда необходимый API не соответствует API вашего класса.

Шаблон Facade обеспечивает упрощенный интерфейс для большей части кода.

Class A{
String setValueFirstHalf(String)
String setValueSecondHalf(String)
Void   getValue()
}

// Pseudo-code for 'wrapper' that is an 'adapter pattern' impl.
// This class 'wraps' A and changes the API
Class WrapsA_Adapter{
String setFirst(String)   {myA.setValueFirstHalf(String)}
String setSecond(String)  {myA.setValueSecondHalf(String)}
Void   get()              {myA.getValue()}
}

// Pseudo-code for 'wrapper' that is an 'facade pattern' impl.
// This class 'wraps' A and changes the API to 'simplify' it.
// Often the 'facade pattern' uses several classes to do its task,
// but it 'can' use just one like we did below. (this example is obviously a stretch)
Class WrapsA_Facade{
String get()
Void   set(String first, String second){
myA.setValueFirstHalf (first);
myA.setValueSecondHalf(second);
}
}

Увидеть: Шаблон адаптера, Фасадный рисунок


Чтобы прямо ответить на ваш вопрос сейчас:

делает ли внедрение зависимостей и классы-обертки против каждого
другие и не могут быть использованы вместе, и что это лучший способ решить
вопрос как это?

Они по своей сути не идут друг против друга.

Вы могли бы очень легко иметь реализацию WrapperFacade, где Facade внедряется с «конкретным» экземпляром интерфейса.

Шаблон адаптера с внедрением зависимостей также будет действителен, если адаптер адаптирует Интерфейс, и вы вводите конкретную реализацию этого интерфейса для его использования.

1

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

Когда вы точно знаете, какой объект вы хотите расширить, тогда лучше всего использовать обычное наследование.

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

ТЛ; др

Если ваш класс всегда будет использоваться как:

$predis = new Predis\Client();
$client = new CacheWrapper($predis);
echo $client->get('key1');

Тогда внедрение зависимостей не добавляет ничего полезного. Однако, если это может быть:

$other = new OtherPredisLikeClass\Client();
$client = new CacheWrapper($other);
echo $client->get('key1');

Затем Dependency Injection позволяет пользователю вашего класса использовать его без переписывания вашего класса.

0

По вопросам рекламы [email protected]