ServiceLocator,let';在ZF2上下文中对它的思考


ServiceLocator, let's thoughts about it in ZF2 context

根据马可的Pivetta思想,这个老问题以及我对另一个问题的回答

我一直在思考在Zend Framework 2中使用我们的服务的更好方法。

实际上,我们可以将ServiceLocatorAwareInterfaceServiceLocatorAwareTrait结合使用。事实上,在ZF3服务定位器将在控制器中删除。他们可能也会删除这个接口,或者建议人们不要使用它,这是有意义的。

我认为如何构建我们的服务的唯一方法是:

不要在服务中使用ServiceLocator,请使用DependencyInjection。

问题是:

有些项目太大了,你要么有:

  • 一个工作流的15个服务类
  • 有15名家属的服务级别
  • 选择你的噩梦

您在服务中可能需要的一些示例:

  • 取回formManager(不能在控制器中调用它)
  • 在通过AJAX和JSON响应向视图返回HTML字符串之前,您可能需要让ViewRenderer渲染模板
  • 您可能需要取回翻译器或ZF2提供的所有服务
  • 获取您的实体经理,如果您有多个数据库,请在此处添加计数
  • 获取其他服务,如MailService、ExportService、ImportService等
  • 如果你必须加载特定的服务取决于客户端(BtoB中的多客户端网站…添加一些服务,因为你不能加载|调用AbstractFactory)

也许对于其中的一些点,它们可以通过我不知道的技巧来解决。

我的问题是:

一项服务有15名或15名以上家属是一种好的做法吗放弃ServiceLocator,在控制器中,但在服务中?

从评论中编辑

为了说明我的观点,我粘贴了我的一个构造函数:

public function __construct(
    ToolboxService $toolboxService,
    EntityService $entityService,
    UserService $userService,
    ItemService $itemService,
    CriteriaService $criteriaService,
    Import $import,
    Export $export,
    PhpRenderer $renderer
) {
    $this->toolboxService = $toolboxService;
    $this->entityService = $entityService;
    $this->userService = $userService;
    $this->emOld = $this->toolboxService->getEmOld();
    $this->emNew = $this->toolboxService->getEmNew();
    $this->serviceLocator = $this->toolboxService->getServiceLocator();
    $this->itemService = $itemService;
    $this->criteriaService = $criteriaService;
    $this->import = $import;
    $this->export = $export;
    $this->renderer = $renderer;
    $this->formManager = $this->toolboxService->getFormManager();
}

正如您所看到的,ToolboxService本身就是一个具有多个依赖关系的对象。此服务在我的应用程序文件夹中,几乎无处不在。我有两个实体经理(连接到两个数据库,但可能很快,我需要第三个…)

您可以看到,我通过依赖关系使用serviceLocator,因此此服务不实现ServiceLocatorAwareInterface。如果我不使用它,我会在的AbstractFactory调用中出错

// Distribute somes orders depends on Clients
$distributionClass = $this->serviceLocator->get(ucfirst($param->type));
            if ($distributionClass instanceof DistributeInterface) {
                $distributionClass->distribute($orders, $key);
            } else {
                throw new 'RuntimeException("invalid_type_provided", 1);
            }

假设您将注入ServiceLocator实例。不能保证ServiceLocator实际上包含了您的硬依赖项,从而打破了DI模式。当使用构造函数依赖项注入时,您可以确保所有需要的服务都是真正可用的。否则,服务的构建将失败。

当使用ServiceLocator时,您将最终进入一个实例化的服务类,其中硬依赖项可能通过ServiceLocator可用,也可能不可用。这意味着你必须编写所有类型的附加逻辑(检查依赖项,抛出异常),以防在你请求ServiceLocator实例的那一刻无法解决依赖项。编写所有这些代码可能比注入15个依赖项要多得多,除此之外,整个服务的逻辑都会很混乱。

此外,您仍然需要添加所有的setter和getter方法,以便能够从ServiceLocator获得服务,并使服务可测试。

IMHO注入15个依赖项比注入ServiceLocator实例更少代码,更易于维护。