Я не слепо следую шаблонам дизайна (нам действительно просто нужно понять объект связи ИМО), но я тоже не хочу быть в неведении о них.
Есть ли название для шаблона проектирования (аналогично Шаблон делегирования, используемый здесь или, может быть, какая-то двойная модель стратегии-вещи-ма-боппера), но вместо того, чтобы переписывать каждый метод и делегировать, вы просто передали бы ссылку ($ this) себе в зависимость? И это разумное решение, чтобы иметь в наборе инструментов для программистов?
Нужен практический пример? Конечно … Продолжайте …
Представьте, что вы используете DI-контейнер и, возможно, у вас есть какой-то метод Controller (MVC), подобный этому:
Рисунок 1:
// Phew! Four dependencies injected here:
public function index(QueryManagerInterface $queryManager, BlogQueryInterface $blogQuery, RenderQueryPDFInterface $queryPDFRenderer, RequestInterface $request) {
// Do some "managing" of a query, then render it into a PDF
$queryManager->setQuery($query);
$queryManager->addInput($request->input());
$queryPDFRenderer->setQuery($query);
$output = $queryPDFRenderer->render();
return $output;
}
Теперь представьте, что ваш метод Controller выглядит следующим образом:
Фигура 2:
// Nice! Just two dependencies!
public function index(BlogQueryInterface $blogQuery, RequestInterface $request) {
$blogQuery->getQueryManager()->addInput($request->input());
$output = $blogQuery->getPDFRenderer()->render();
return $output;
}
Как я это сделал? Весь код одинаков во всех этих классах, за исключением того, что я обновил класс $ blogQuery:
Class BlogQuery Implements BlogQueryInterface, QueryManageableInterface, PDFRenderableInterface {
public function __construct(QueryManagerInterface $manager, $PDFRendererInterface $pdfRenderer){
// Here I pass a reference of this own class into its dependencies
$this->manager = $manager->setQuery($this);
$this->pdfRenderer = $pdfRenderer->setQuery($this);
}
public function getQueryManager() { return $this->manager; }
public function getPDFrenderer() { return $this->pdfRenderer; }
...
}
Плюсы рисунка 2:
Какой шаблон я использовал на рисунке 2? Каковы минусы такого подхода? Такой подход считается хорошей практикой?
Это выглядит для меня как Шаблон посетителя, где __construct
делает QueryManagerInterface
а также PDFRendererInterface
посетители BlogQuery
,
Я не хочу слишком увлекаться плюсами и минусами шаблонов программирования, потому что по большей части они будут прежде всего основанный на мнении. Но один довольно объективный результат шаблона посетителя состоит в том, что он имеет тенденцию к большему отскоку между файлами / классами, чем другие опции, что может затруднить загрузку программы чтения для читателя. В конечном счете, «хорошая практика ООП» сводится к опыту, суждению и, вероятно, переписыванию его три раза.
Я хочу отметить, что вы на самом деле не уменьшили зависимости вашего index
функция. Да, требуется меньше аргументов, но он все еще знает, как QueryManagerInterface
а также RenderQueryPDFInterface
вести себя. Если эти интерфейсы изменятся (например, переименуйте addInput
или же render
), ваш код в index
также должен измениться. Когда вы тестируете index
Вам все еще нужно настроить или смоделировать эти два объекта для прохождения теста. Если вы не можете скрыть это поведение внутри BlogQueryInterface
а также RequestInterface
(см. также Закон Деметры), index
имеет одинаковые зависимости в обоих подходах.
Других решений пока нет …