Dependency injection 依赖注入中的一些概念

Dependency injection 依赖注入中的一些概念,dependency-injection,Dependency Injection,我是依赖注入的新手,一直在StackOverflow和其他网站上阅读相关书籍。实际上,我在正确使用它方面遇到了困难 为了解释这个问题,下面是一个我不确定如何使用DI的基本情况: 假设我有一个对象,它将在几个不同的类中使用。然而,为了使这个对象可用,它需要一些我在启动时没有的参数 我可以看到,使用DI实现这一点的一种可行方法是创建此对象的空白实例、使用必要参数初始化它的方法以及是否初始化它的标志 对我来说,这感觉像是黑客攻击,因为对象还不应该真正存在,我只是在传递一个容器,等待负责的代码初始化它。

我是依赖注入的新手,一直在StackOverflow和其他网站上阅读相关书籍。实际上,我在正确使用它方面遇到了困难

为了解释这个问题,下面是一个我不确定如何使用DI的基本情况: 假设我有一个对象,它将在几个不同的类中使用。然而,为了使这个对象可用,它需要一些我在启动时没有的参数

我可以看到,使用DI实现这一点的一种可行方法是创建此对象的空白实例、使用必要参数初始化它的方法以及是否初始化它的标志


对我来说,这感觉像是黑客攻击,因为对象还不应该真正存在,我只是在传递一个容器,等待负责的代码初始化它。这就是为什么要这样做,还是我没有抓住重点?

这确实是一件很难在开始使用DI时了解的事情,也是一件很难解释的事情

您认为创建一个“空白”对象(稍后将通过一个方法初始化)可能是一个次优的解决方案,这是正确的——一个对象应该能够在任何时候完成它的工作
Initialize()
方法是MarkSeemann在其著作.NET中的依赖注入中所称的“时间耦合”。这是一种反模式,使使用对象的代码依赖于该对象的内部工作,从而破坏封装

问题是当所需信息可用时,“初始化它的责任代码”是什么,它从哪里获得信息,以及它如何访问对象以初始化它。理想情况下,该初始化代码本身将被注入到对象中,并且每当访问对象的方法/属性时,它都会从另一个依赖项请求初始化

另外,如果
IsInitialized
标志返回false,会发生什么情况?这仍然是有效的程序状态吗

一般来说,作为依赖注入对象图中的对象,我应该知道创建时的所有“配置”数据,或者知道可以将其提供给我的人(某个人是作为依赖注入的另一个对象)

如果您能提供更多关于对象需要什么类型的参数以及这些参数的来源的详细信息,可能会有所帮助

编辑

你在评论中所描述的几乎正是我第一次遇到这种问题;这里有个问题,所以我当时就发了

重要的是以这样一种方式构建单个类(通常,可能会有例外,但这是一个经验问题),即假定类需要的所有东西都存在。当程序运行时,需要有其他类来确保假设不会失败

Setter注入是我通常不必避免所说的时间耦合的东西;根据MarkSeemann的说法,setter注入通常只应该在您已经有了一个好的默认值,您只需要通过setter进行覆盖时使用。但是,在这种情况下,如果没有依赖关系,对象将无法正常工作

这可能不是实现这一点的最优雅的方式(我通常可以在非常封闭的代码环境中应用DI,而不必担心UI),但它可以工作(有点-它可以编译,但仍然是伪代码):

公共类主窗体
{
专用只读IDataManager_dataManager;
专用只读IConnectionProvider\u connectionProvider;
专用只读IConnectionReceiver\u connectionReceiver;
公共主窗体(IDataManager dataManager、IConnectionProvider connectionProvider、IConnectionReceiver connectionReceiver)
{
这是。_dataManager=dataManager;
这。_connectionProvider=connectionProvider;
这。_connectionReceiver=connectionReceiver;
}
公共无效BTN连接\单击()
{
IConnection connection=this.\u connectionProvider.GetConnection();
if(null!=连接)
{
此._connectionReceiver.SetConnection(连接);
此.SetFormControlsEnabled(true);
}
}
私有void SetFormControlsEnabled(bool doEnable)
{
}
}
公共接口IConnectionProvider
{
i连接GetConnection();
}
公共接口IConnectionReceiver
{
无效设置连接(i连接连接);
}
公共接口i连接
{
IConnectionWebService连接WebService{get;}
}
公共类连接桥:IConnection,IConnectionReceiver
{
专用I连接\u连接;
#区域I连接接收器成员
公共连接(IConnection连接)
{
这个。_连接=连接;
}
#endregion I连接接收器成员
#区域i连接成员
公共IConnectionWebService连接WebService
{
获取{返回此。\u connection.ConnectionWebService;}
}
#端区
}
公共接口IConnectionWebService{}
公共接口IDataManager{}
公共类数据管理器:IDataManager
{
公共数据管理器(IConnection连接)
{
}
}
因此,
MainForm
是将所有内容结合在一起的东西。它从禁用控件开始,因为它知道它们需要一个工作的
IDataManager
,并且(按照惯例)需要一个连接。单击“连接”按钮时,表单要求其
IConnectionProvider
依赖项进行连接。它不在乎这种联系来自哪里;连接提供程序可能会显示另一个表单以请求凭据,也可能只是从文件中读取凭据

然后表单知道必须将连接传递到
IConnectionReceiver
实例,然后可以启用所有控件。这不是我的错