对 DI、IoC 和服务定位器的困惑
本文关键字:定位器 服务 DI IoC | 更新日期: 2023-09-27 18:34:32
我已经阅读了有关IoC,dip,DI和服务定位器的各种文章,但我有点困惑,这是因为有些文章的例子太模糊,而其他一些文章只有一些具体的例子,没有提到其他情况。
您能否为我澄清这一点,看看下面的示例并简要解释哪些示例与哪种模式匹配?
-
手动将接口传递给构造函数:
class Consumer { public Consumer(IStore store){...} } ... Consumer c = new Consumer(new ConcreteStore());
-
与第一个示例相同,但使用了一些第三方库(Unity,Windsor,Ninject(
-
与第一个示例相同,但使用 BaseStore 类而不是 IStore 接口
-
将依赖项传递给其他方法,而不是构造函数:
class Consumer { public BySomething(IStore store){...} } ... Consumer c = new Consumer(); c.BySomething(new ConcreteStore());
-
传递在其他接口中屏蔽的依赖项(此解决方案的奖励 - 当在"世界"中发明了一些其他东西并且消费者希望使用它们时,我们不必更改构造函数参数,而只需更新 IWorld;我们可以在测试时完全用其他东西替换整个世界(:
interface IWorld { IDictionary<string,IStore> Stores { get; set; } IDictionary<string,ICityMap> Maps { get; set; } ... } class Consumer { public Consumer(IWorld world){...} public BySomething(string store, string city){...} } ... IWorld myWorld = new HeavenlyWorld(); ... // adding stores, maps and whatnot Consumer c = new Consumer(myWorld);
一个子问题:在这种情况下,IWorld 是否完全是服务定位器?
-
传递回调函数或委托(在本例中为 .NET 操作(:
c.BySomething(store, city, new Action(() => {...} ));
我添加了这种情况,因为文章控制反转指出每个回调都是 IoC。是真的吗?
您列出的所有内容都是依赖注入的一种形式。
- "穷人的"DI
- 使用 IoC 容器的 DI
- "穷人的"DI又来了。无论您使用的是接口还是抽象类,DI 都有效。
- 方法注入
- 我不确定你在这里问什么。听起来您想在运行时更改 IWorld 的实例,这可能是属性注入而不是构造函数注入的情况。属性通常用于可选依赖项或可以更改的依赖项。然后,是否在运行时使用服务定位器或其他方式设置该依赖项取决于您。要考虑的另一件事是,IWorld 可能只依赖于上下文,在这种情况下,您可以进行上下文降级构造函数注入,其细节超出了本文的范围。
- 与 DI 无关
每次将依赖项作为构造函数/方法参数传递时,这就是依赖项注入。它可以是手动的,就像在大多数示例中一样,也可以使用 DI 容器(又名 IoC 容器(自动执行。
使用容器意味着使用 deps 的对象由容器构造。您可以直接向容器请求该服务,在这种情况下,有一个静态属性或方法(想想 asp.net mvc 中的 DependecyResolver(公开该服务。在这种情况下,您使用的是服务定位器模式。在您的示例中,IWork 不是定位器,它只是一个依赖项。
若要继续依赖项解析程序示例,请将所有相关类型注册到容器中,生成容器,然后注册为依赖项解析程序。然后,asp.net mvc 框架使用解析器(服务定位器 - SL(来实例化控制器、视图以及它们所需的所有部门。
使用 SL 模式作为框架的一部分是可以的,但如果在应用中使用它来实例化对象,则不行,因为它将代码耦合到定位器。有时是唯一的解决方案,但 99% 你只是一个反模式。