我正在设计一个非常模块化的Angular项目 - sections of the app can be enabled and disabled for different clients using Webpack.这个结构对我来说效果很好,但我遇到的一个问题是如何处理可能并不总是存在的服务。
我当前的解决方案非常简单 - 我使用$injector.has()
检查服务当前是否存在,如果是,我使用$injector.get()
来抓取它:
function initialize($injector) {
if ($injector.has("barcode")) {
let barcode = $injector.get("barcode");
// Do stuff with the barcode service
}
}
这似乎有效 - 但是,我找不到关于这种模式的使用的信息,以及它是否有任何潜在的缺点。
所以,我的问题是:
答案 0 :(得分:2)
这可能是达到你想要的最佳方式;但是,在执行此操作时,请注意您正从 Dependency Injection (DI)转移到 Service Locator 模式。
以下from the Angular 2 docs非常重要(强调我的):
我们避免使用这种技术,除非我们真正需要它。它鼓励像我们在这里看到的粗心的抓包方法。很难解释,理解和测试。我们无法通过检查构造函数来了解这个类需要什么或它将做什么。它可以从任何祖先组件获取服务,而不仅仅是它自己的组件。我们不得不通过实施来发现它的作用。
当框架开发人员必须通用且动态地获取服务时,可采用此方法。
(旁白:值得阅读dependency injection in Angular 2即将发生的事情 - 可选的依赖项,工厂提供商等。)
Angular 1的docs on the matter引用它The Law of Demeter(这当然更像是一条指导而不是法律,对吧?)。
无论如何,还需要注意一些其他事项:
您将不会被警告(通过errors thrown)循环依赖关系使用它;事实上,这通常是人们用来解决这些警告的技术。
由于您现在除了注入的内容之外还依赖于$ injector,因此您的单元测试需要模拟$ injector,或使用类似module('moduleThatIsUsingInjectorExplicitly', function($provide) { $provide.value('barcode', barCodeMock);}
的内容。
正如上面的引文中所提到的,由于这些“可选”的依赖关系并未在通常的地方定义,因此您的代码将不那么明确。
很多其他关于服务定位器模式的读数,并将其与DI进行对比。有趣的是,但对我们的实际意义可能有限,特别是因为JavaScript缺乏Interface / Abstract和Angular 1的DI实现意味着实际的差异点较少。