这种设计模式有名称吗(将你自己传递到你自己的依赖项中),这种技术有哪些缺陷?
Is there a name for this design pattern (pass yourself into one of your own dependencies), and what are the pitfalls of such a technique?
我不会盲目地遵循设计模式(我们真的只需要了解对象通信 IMO),但我也不想对它们一无所知。
是否有设计模式的名称(类似于 Delegation Pattern used here 或某些双重调度策略模式的东西-a-ma-bopper)但不是重写每个方法和委托,您只是将对自己的引用($this)传递到依赖项中吗?这是程序员工具箱中的合理解决方案吗?
需要一个实际的例子吗?当然...继续...
假设您正在使用 DI 容器并且可能有一些像这样的控制器 (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 方法如下所示:
图二:
// Nice! Just two dependencies!
public function index(BlogQueryInterface $blogQuery, RequestInterface $request) {
$blogQuery->getQueryManager()->addInput($request->input());
$output = $blogQuery->getPDFRenderer()->render();
return $output;
}
我是怎么做到的?所有这些 classes 中的所有代码都是相同的,除了我更新了 $blogQuery:
的 class
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的优点是:
- 减少对控制器方法的依赖
- 更少的代码行
- 组合优于继承(更松散耦合?)。
- 无需像使用委托模式时那样"type a bunch of repetitive methods"。
- 比较好理解。仅注入 BlogQuery 和 Request 似乎捕获了主要上下文。 (主观)
我在图 2 中使用了什么模式?这种方法的缺点是什么?这种方法被认为是好的 oop 实践吗?
这在我看来像 Visitor Pattern,其中 __construct
使 QueryManagerInterface
和 PDFRendererInterface
访问者访问 BlogQuery
。
我不想过多涉及编程模式的利弊,因为在大多数情况下,这些都是 primarily opinion-based。但是,访问者模式的一个漂亮的 objective 结果是它往往比其他选项在 files/classes 之间有更多的跳动,这会使 reader 更难以加载到他们的脑海中。最终,"good OOP practice" 归结为经验、判断,并且可能重写了三次。
我确实想指出您并没有真正减少 index
函数的依赖性。是的,它需要更少的参数,但它仍然知道 QueryManagerInterface
和 RenderQueryPDFInterface
的行为。如果这些接口发生变化(例如,重命名 addInput
或 render
),您在 index
中的代码也必须更改。当您测试 index
时,您仍然必须设置或模拟这两个对象才能使测试通过。除非您可以在 BlogQueryInterface
和 RequestInterface
中隐藏该行为(另请参阅 Law of Demeter),否则 index
在这两种方法中具有完全相同的依赖关系。
我不会盲目地遵循设计模式(我们真的只需要了解对象通信 IMO),但我也不想对它们一无所知。
是否有设计模式的名称(类似于 Delegation Pattern used here 或某些双重调度策略模式的东西-a-ma-bopper)但不是重写每个方法和委托,您只是将对自己的引用($this)传递到依赖项中吗?这是程序员工具箱中的合理解决方案吗?
需要一个实际的例子吗?当然...继续...
假设您正在使用 DI 容器并且可能有一些像这样的控制器 (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 方法如下所示:
图二:
// Nice! Just two dependencies!
public function index(BlogQueryInterface $blogQuery, RequestInterface $request) {
$blogQuery->getQueryManager()->addInput($request->input());
$output = $blogQuery->getPDFRenderer()->render();
return $output;
}
我是怎么做到的?所有这些 classes 中的所有代码都是相同的,除了我更新了 $blogQuery:
的 classClass 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的优点是:
- 减少对控制器方法的依赖
- 更少的代码行
- 组合优于继承(更松散耦合?)。
- 无需像使用委托模式时那样"type a bunch of repetitive methods"。
- 比较好理解。仅注入 BlogQuery 和 Request 似乎捕获了主要上下文。 (主观)
我在图 2 中使用了什么模式?这种方法的缺点是什么?这种方法被认为是好的 oop 实践吗?
这在我看来像 Visitor Pattern,其中 __construct
使 QueryManagerInterface
和 PDFRendererInterface
访问者访问 BlogQuery
。
我不想过多涉及编程模式的利弊,因为在大多数情况下,这些都是 primarily opinion-based。但是,访问者模式的一个漂亮的 objective 结果是它往往比其他选项在 files/classes 之间有更多的跳动,这会使 reader 更难以加载到他们的脑海中。最终,"good OOP practice" 归结为经验、判断,并且可能重写了三次。
我确实想指出您并没有真正减少 index
函数的依赖性。是的,它需要更少的参数,但它仍然知道 QueryManagerInterface
和 RenderQueryPDFInterface
的行为。如果这些接口发生变化(例如,重命名 addInput
或 render
),您在 index
中的代码也必须更改。当您测试 index
时,您仍然必须设置或模拟这两个对象才能使测试通过。除非您可以在 BlogQueryInterface
和 RequestInterface
中隐藏该行为(另请参阅 Law of Demeter),否则 index
在这两种方法中具有完全相同的依赖关系。