Различие паттернов Dependency Injection и Strategy

andruhaa

Новичок
Кто то может доходчиво объяснить разницу?

Как по мне оба решают одну и туже задачу: "Отделяют процедуру выбора алгоритма от реализации, предоставляя возможность выбора алгоритма на основе контекста".

Или я упускаю какую то особенность или мотивацию выбора одного из них?
 

MiksIr

miksir@home:~$
Статегия говорит о том, что мы можем в разных классах за одним интерфейсом спрятать разный алгоритм, и давать объект того или иного класса. А DI говорит о том, как вообще один объект может добраться до любого другого объекта. Это паттерны существующие без проблем вместе и одновременно и Стратегия вполне может использовать DI.
 

itprog

Cruftsman
это как bridge и adapter. Принцип один и тот же, а используются в разных случаях.

Как переписать следующий код используя паттерн strategy не вызовет вопросов, а "как переписать используя DI" звучит немного глупо.
PHP:
if (operation == "multiply") {
    return a * b;
} elseif (operation == "divide") {
    return a / b;
}
В случае со Strategy, сам объект может выбрать и создать нужную стратегию, а для того, чтобы соответствовать DI, нужно будет устранить это.
 

MiksIr

miksir@home:~$
В случае со Strategy, сам объект может выбрать и создать нужную стратегию, а для того, чтобы соответствовать DI, нужно будет устранить это.
"сам объект" - это Клиент? Он не выбирает сам, он знает только про интерфейс объекта, который ему дает Контекст.
 

andruhaa

Новичок
Статегия говорит о том, что мы можем в разных классах за одним интерфейсом спрятать разный алгоритм, и давать объект того или иного класса. А DI говорит о том, как вообще один объект может добраться до любого другого объекта. Это паттерны существующие без проблем вместе и одновременно и Стратегия вполне может использовать DI.
Ну насколько я понимаю то DI так же требует что бы классы реализации имени общий интерфейс, иначе как класс программы будет знать как использовать переданный ему объект?

Прошу конечно простить, может я и не вижу очевидного.

Рассмотрим пример выше.
PHP:
interface IMethod
{
  function calculate($oprrand1, $oprrand2);
}

calss Multiplication implements IMethod{
  function calculate($oprrand1, $oprrand2) {
    return $oprrand1 * $oprrand2;
  }
}

class Division implements IMethod{
  function calculate($oprrand1, $oprrand2) {
    if(oprrand2 == 0)
          throw new Exception('Деление на ноль - невозможно.');

    return $oprrand1 / $oprrand2;
  }
}

class Operation  {
   protected $_method

   function __construct (IMethod $method) {
      $this->_method = $method;
   }

   function write($oprrand1, $oprrand2) {
      echo "Result ".$this->_method->calculate($oprrand1, $oprrand2);
   }
}

$operation1 = new Operation(new Division);  
$operation2 = new Operation(new Division);  
$operation1->write(4,2);
$operation2->write(4,2);
Пропускаем банальность примера.
Вот в методе Operation::write что в случаи Стратегии что в случаи DI, все равно нужно быть уверенным что полученный объект содержит метод calculate, и без интерфейса тут никак.

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

PHP:
interface IComponent {
   function getName();
}

class DBComponent implements IComponent  {
     function getName() {
         return "db";
     }
}

class RouterComponent implements IComponent  {
     function getName() {
         return "router";
     }
}

class KernelComponent implements IComponent  {
     function getName() {
         return "kernel";
     }
}

class App() {
  $_components = array();

  function addComponent(IComponent $component, $name=null) {
     $this->_components[$name===null?$component->getName():$name] = $component;
  }

  function getComponent($name) { 
      if(!isset($this->_components[$name])) {
         //Тут можно реализовать поиск нужного компонента и авторегистрацию
         return null;
      }

      return  $this->_components[$name];
  }
}

$app = new App;
// Загрузку компонентов можно реализовать перебором конфига
$app->addComponent(new DBComponent);
$app->addComponent(new DBComponent, "db2");
$app->addComponent(new RouterComponent);
$app->addComponent(new KernelComponent);

$app->getCompontnt("db")->runQuery($sql);
Все равно в голове каша :(
 

MiksIr

miksir@home:~$
В первом примере у вас Стратегия + DI.

Стратегия не говорит каким способом один класс попадет в другой - это может быть абстрактная фабрика или еще что-то.

DI говорит просто, что очень плохо тянуть (запрашивать/создавать объекты внутри вашего класса), а вот заталкивать извне - хорошо. При этом DI ничего не говорит о тех объектах, которые будут заталкиваться, это уже выходит за рамки DI.

Я конечно могу ошибаться, я вообще в этом нехрена ни в зуб ногой =)
 
Сверху