这种设计模式是否有一个名称(让自己进入自己的依赖项之一),这种技术的陷阱是什么?


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),但我也不想忽视它们。

是否有一个设计模式的名称(类似于这里使用的委托模式或可能是一些双重调度策略模式的东西),但不是重写每个方法和委托,您只需将引用($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方法是这样的:

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

  • 减少对控制器方法的依赖
  • 更少的代码行
  • 组合优于继承(更松散耦合?)。
  • 不需要像使用委托模式那样"输入一堆重复的方法"。
  • 更容易理解。只注入BlogQuery和Request似乎捕获了主要上下文。(主观)

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

这看起来像访客模式,其中__construct使QueryManagerInterfacePDFRendererInterface访问BlogQuery

我不想过多地涉及编程模式的利弊,因为在大多数情况下,这些主要是基于意见的。但是,访问者模式的一个相当客观的结果是,与其他选项相比,它倾向于在文件/类之间有更多的跳跃,这可能会使读者更难将其加载到他们的脑海中。最终,"好的OOP实践"归结为经验、判断,可能还要重写三次。

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