已经发布了几个关于依赖注入的具体问题的问题,例如何时使用它以及它有哪些框架.然而,
什么是依赖注入以及何时/为什么应该或不应该使用它?
language-agnostic design-patterns dependency-injection terminology
根据Martin Fowler撰写的论文,控制反转是程序控制流程被颠倒的原则:代替程序员控制程序流程,外部源(框架,服务,其他组件)控制它.这就像我们把东西塞进别的东西.他提到了一个关于EJB 2.0的例子:
例如,会话Bean接口定义ejbRemove,ejbPassivate(存储到辅助存储)和ejbActivate(从被动状态恢复).你无法控制何时调用这些方法,只是它们的作用.容器打电话给我们,我们不打电话给它.
这导致框架和库之间的区别:
控制反转是使框架与库不同的关键部分.库本质上是一组可以调用的函数,这些日子通常组织成类.每个调用都会执行一些操作并将控制权返回给客户端.
我认为,DI是IOC的观点,意味着对象的依赖性被颠倒了:相反,它控制着自己的依赖关系,生命周期......还有其他东西为你做.但是,正如你用手告诉我的DI,DI不一定是IOC.我们仍然可以有DI而没有IOC.
然而,在本文中(来自pococapsule,另一个IOC C/C++框架),它表明,由于IOC和DI,IOC容器和DI框架远远优于J2EE,因为J2EE将框架代码混合到组件中因此不能成为普通的旧Java/C++对象(POJO/POCO).
除依赖注入模式之外的控制容器的反转(存档链接)
附加阅读以了解旧的基于组件的开发框架的问题是什么,这导致了上面的第二篇论文:为什么以及什么是控制反转(存档链接)
我的问题:IOC和DI究竟是什么?我很迷惑.基于pococapsule,IOC比仅仅反转对象或程序员和框架之间的控制更重要.
最近我读过Mark Seemann关于Service Locator反模式的文章.
作者指出ServiceLocator为反模式的两个主要原因:
API使用问题(我完全可以使用)
当类使用服务定位器时,很难看到它的依赖关系,因为在大多数情况下,类只有一个PARAMETERLESS构造函数.与ServiceLocator相比,DI方法通过构造函数的参数显式地暴露依赖关系,因此在IntelliSense中很容易看到依赖关系.
维护问题(让我感到困惑)
请考虑以下示例
我们有一个使用服务定位器方法的类'MyType':
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们要为类'MyType'添加另一个依赖项
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
// new dependency
var dep2 = Locator.Resolve<IDep2>();
dep2.DoSomething();
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我的误解开始的地方.作者说:
要判断你是否引入了一个重大改变,要变得更加困难.您需要了解使用Service Locator的整个应用程序,并且编译器不会帮助您.
但是等一下,如果我们使用DI方法,我们将在构造函数中引入与另一个参数的依赖关系(在构造函数注入的情况下).问题仍然存在.如果我们忘记设置ServiceLocator,那么我们可能忘记在IoC容器中添加新的映射,并且DI方法将具有相同的运行时问题.
此外,作者还提到了单元测试的难点.但是,我们不会有DI方法的问题吗?我们不需要更新所有实例化该类的测试吗?我们将更新它们以传递一个新的模拟依赖项,以使我们的测试可编译.我没有看到更新和时间花费带来任何好处.
我不是想捍卫Service Locator方法.但这种误解让我觉得我失去了一些非常重要的东西.有人可以消除我的怀疑吗?
更新(摘要):
我的问题"服务定位器是反模式"的答案实际上取决于具体情况.我绝对不会建议你从工具列表中删除它.当您开始处理遗留代码时,它可能会变得非常方便.如果你很幸运能够处于项目的最初阶段,那么DI方法可能是更好的选择,因为它比Service Locator有一些优势.
以下是主要的不同之处,这些差异使我不相信我的新项目使用Service Locator:
有关详细信息,请阅读下面给出的优秀答案.
design-patterns dependency-injection anti-patterns service-locator
我正在探索依赖注入,并且在整个地方使用术语组合根.那是什么?
乍一看,服务定位器模式与我的抽象工厂模式看起来相同.它们似乎都具有相同的用途(您查询它们以接收抽象服务的实例),并且当我阅读有关依赖注入时它们都被提及.
但是,我已经看到服务定位器模式被描述为一个糟糕的想法,但在至少一个主要的依赖注入框架中看到了对抽象工厂模式的直接支持.
如果它们不相同,有什么区别?
我目前正在权衡DI和SL之间的优缺点.但是,我发现自己处于以下问题22中,这意味着我应该只使用SL作为一切,并且只在每个类中注入一个IoC容器.
DI Catch 22:
一些依赖项,如Log4Net,根本不适合DI.我称之为元依赖关系并认为它们对调用代码应该是不透明的.我的理由是,如果一个简单的类'D'最初是在没有记录的情况下实现的,然后增长到需要记录,那么依赖类'A','B'和'C'现在必须以某种方式获得这种依赖并将其从'A'到'D'(假设'A'组成'B','B'组成'C',依此类推).我们现在已经进行了重要的代码更改,因为我们需要登录一个类.
因此,我们需要一种不透明的机制来获取元依赖性.我想到了两个:Singleton和SL.前者具有已知的局限性,主要是关于刚性范围的能力:最好的是Singleton将使用存储在应用程序范围内的抽象工厂(即在静态变量中).这允许一些灵活性,但并不完美.
更好的解决方案是将IoC容器注入此类,然后使用该类中的SL从容器中解析这些元依赖关系.
因此,捕获22:因为类现在正在注入IoC容器,那么为什么不使用它来解析所有其他依赖项呢?
我非常感谢你的想法:)
c# singleton dependency-injection dependency-management service-locator
可能重复:
依赖注入与工厂模式
有人可以解释(简单例子)工厂模式和反转控制模式之间的区别.最好使用.NET2.0
好的,我有以下情况.我原来有一些像这样的代码:
public class MainBoard {
private BoardType1 bt1;
private BoardType2 bt2;
private BoardType3 bt3;
...
private readonly Size boardSize;
public MainBoard(Size boardSize) {
this.boardSize = boardSize;
bt1 = new BoardType1(boardSize);
bt2 = new BoardType2(boardSize);
bt3 = new BoardType3(boardSize);
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我决定重构该代码,以便注入类的依赖项,而不是:
public class MainBoard {
private IBoardType1 bt1;
private IBoardType2 bt2;
private IBoardType3 bt3;
...
private Size boardSize;
public MainBoard(Size boardSize, IBoardType1 bt1, IBoardType2 bt2, IBoardType3 bt3) {
this.bt1 = bt1;
this.bt2 = bt2;
this.bt3 = bt3;
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是如何处理Board …
我一直在努力学习依赖注入,并一直在阅读和尝试编写一个类似于此的小依赖注入容器:http://fabien.potencier.org/article/12/do-you-need-a-dependency步喷射容器
令我困惑的一件事是:
依赖注入容器不仅仅是工厂模式的美化实现吗?
如果是这样,为什么不直接称之为,为什么需要一个奇特的术语只是为了混淆问题.
如果不是,有人可以解释我在这里缺少的东西吗?
我有两个版本的工厂类基于该文章设计
http://www.oodesign.com/factory-pattern.html
public abstract class Employee
{
public string Name { get; set; }
protected string Role { get; set; }
public abstract string GetRole();
}
public class Manager : Employee
{
public Manager()
{
Role = "MGR";
}
public override string GetRole()
{
return this.Role;
}
}
Run Code Online (Sandbox Code Playgroud)
版本1:简单,违反开放式关闭原则
当我添加一个新的具体类时,每次都需要更改SimpleEmployeeFactory
public class SimpleEmployeeFactory
{
public static Employee GetEmployee(int typeId)
{
switch (typeId)
{
case 1:
return new Manager();
case 2:
return new TechnicalLead();
default:
return null; //if the id …Run Code Online (Sandbox Code Playgroud) 我正在研究一个模型,可以用一堆不同的车辆做一些事情。每个 Vehicle 都应该做一些事情,但每种 Vehicle 类型做不同的事情。所以我使用 .NET Framework 以这种方式实现了它:
abstract class Vehicle
{
abstract void DoStuff()
}
class Car : Vehicle
{
override void DoStuff()
{
//Do some Car stuff here
}
}
class Motorcycle : Vehicle
{
override void DoStuff()
{
//Do some Motorcycle stuff here
}
}
class Model
{
RunModel(Vehicle[] vehicleCollection)
{
foreach(Vehicle currentVehicle in vehicleCollection)
{
currentVehicle.DoStuff()
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的程序的核心功能,它按预期工作。现在我应该根据每辆车所做的事情输出报告。每种类型的车辆都应该输出不同类型的报告,所以我为它做了一个类似的解决方案:
abstract class Vehicle
{
abstract void DoStuff();
abstract Report GetReport();
}
class Car : Vehicle
{ …Run Code Online (Sandbox Code Playgroud) c# ×5
java ×2
oop ×2
dependencies ×1
factory ×1
polymorphism ×1
refactoring ×1
singleton ×1
spring ×1
terminology ×1