这种设计模式有名称吗(将你自己传递到你自己的依赖项中),这种技术有哪些缺陷?

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的优点是:


我在图 2 中使用了什么模式?这种方法的缺点是什么?这种方法被认为是好的 oop 实践吗?

这在我看来像 Visitor Pattern,其中 __construct 使 QueryManagerInterfacePDFRendererInterface 访问者访问 BlogQuery

我不想过多涉及编程模式的利弊,因为在大多数情况下,这些都是 primarily opinion-based。但是,访问者模式的一个漂亮的 objective 结果是它往往比其他选项在 files/classes 之间有更多的跳动,这会使 reader 更难以加载到他们的脑海中。最终,"good OOP practice" 归结为经验、判断,并且可能重写了三次。

我确实想指出您并没有真正减少 index 函数的依赖性。是的,它需要更少的参数,但它仍然知道 QueryManagerInterfaceRenderQueryPDFInterface 的行为。如果这些接口发生变化(例如,重命名 addInputrender),您在 index 中的代码也必须更改。当您测试 index 时,您仍然必须设置或模拟这两个对象才能使测试通过。除非您可以在 BlogQueryInterfaceRequestInterface 中隐藏该行为(另请参阅 Law of Demeter),否则 index 在这两种方法中具有完全相同的依赖关系。