Dependency injection 依赖注入:从混凝土工厂恢复混凝土对象可以吗

Dependency injection 依赖注入:从混凝土工厂恢复混凝土对象可以吗,dependency-injection,inversion-of-control,Dependency Injection,Inversion Of Control,我对依赖注入还比较陌生,我写了一个很棒的小应用程序,它的工作原理和马克·希曼告诉我的一模一样,整个世界都很棒。我甚至给它增加了一些额外的复杂性,只是为了看看我是否可以使用DI来处理它。我可以,快乐的日子 然后我把它带到了一个真实的应用程序中,花了很长时间挠头。Mark告诉我,我不允许使用'new'关键字来实例化对象,我应该让IoC替我做这件事 但是,假设我有一个存储库,我希望它能够返回一个列表,因此: public interface IThingRepository { public IEn

我对依赖注入还比较陌生,我写了一个很棒的小应用程序,它的工作原理和马克·希曼告诉我的一模一样,整个世界都很棒。我甚至给它增加了一些额外的复杂性,只是为了看看我是否可以使用DI来处理它。我可以,快乐的日子

然后我把它带到了一个真实的应用程序中,花了很长时间挠头。Mark告诉我,我不允许使用'new'关键字来实例化对象,我应该让IoC替我做这件事

但是,假设我有一个存储库,我希望它能够返回一个列表,因此:

public interface IThingRepository
{
 public IEnumerable<IThing> GetThings();
}
<代码>公共界面信息存储库 { 公共IEnumerable GetThings(); } 当然,这个接口的至少一个实现必须实例化某些东西的实例?而且,允许ThingRepository更新一些相关的东西似乎并没有那么糟糕

我可以转而传递一个POCO,但在某个时刻,我必须将POCO转换成一个业务对象,这需要我更新一些东西

这种情况似乎每次我想要一些在合成根中不可知的东西时都会发生(例如,我们只是在以后找到这些信息——例如在查询数据库时)

有人知道在这种情况下最好的做法是什么吗

Mark告诉我不允许使用“new”关键字来实例化对象

这不是马克·希曼告诉你的,也不是他的意思。您必须明确区分一端的服务(由您的组合根控制)和另一端的原语、实体、DTO、视图模型和消息。服务是免费的。您应仅防止在服务类型上使用
new
。例如,阻止重新生成字符串是愚蠢的


因为在您的示例中,服务是一个域对象,所以假设存储库返回域对象似乎是合理的。域对象是可更新的,没有理由不手动
新建它们。

除了Steven的答案,我认为特定工厂可以更新其创建的特定匹配实现

更新 另外,请检查注释,特别是注释,这些注释说明了如何创建新实例

例如:

public interface IContext {
    T GetById<T>(int id);
}

public interface IContextFactory {
    IContext Create();
}

public class EntityContext : DbContext, IContext {
    public T GetById<T>(int id) {
        var entity = ...;   // Retrieve from db
        return entity;
    }
}

public class EntityContextFactory : IContextFactory {
    public IContext Create() {
        // I think this is ok, since the factory was specifically created
        // to return the matching implementation of IContext.
        return new EntityContext(); 
    }
}
公共接口IContext{
T GetById(int-id);
}
公共接口IContextFactory{
IContext Create();
}
公共类EntityContext:DbContext,IContext{
公共T GetById(int-id){
var entity=…;//从数据库检索
返回实体;
}
}
公共类EntityContextFactory:IContextFactory{
公共IContext创建(){
//我认为这没关系,因为工厂是专门创建的
//返回IContext的匹配实现。
返回新的EntityContext();
}
}

谢谢大家的回答,他们让我得出了以下结论

Mark在我正在阅读的书(“.NET中的依赖注入”)中区分了稳定依赖项和不稳定依赖项。可以随意创建稳定的依赖项(如字符串)。不稳定的依赖项应移到seam/接口后面

依赖项是与我们正在编写的程序集中不同的程序集中的任何内容

不稳定的依赖项是以下任一项

  • 它需要设置一个运行时环境,例如数据库、web服务器,甚至可能是文件系统(否则它将无法扩展或测试,这意味着如果我们愿意,我们无法进行后期绑定)
  • 它还不存在(否则我们无法进行并行开发)
  • 它需要一些并非安装在所有机器上的东西(否则会导致测试困难)
  • 它包含非确定性行为(否则无法很好地测试)
所以这一切都很好

但是,我经常在同一个部件中的接缝后面隐藏东西。我发现这对测试非常有帮助。例如,如果我正在进行复杂的计算,则不可能一次性测试整个计算。如果我将计算分成许多较小的类并将它们隐藏在接缝后面,那么我可以很容易地将任意中间结果注入到计算类中

因此,在仔细思考之后,我得出以下结论:

  • 创建一个稳定的依赖项总是可以的
  • 永远不要直接创建不稳定的依赖项
  • 在程序集中使用接缝是很有用的,尤其是用来分解大类并使它们更容易测试

作为对我最初问题的回答,从混凝土工厂安装混凝土对象是可以的。

谢谢,这个链接非常明确地说明了这是一件可以做的事情。谢谢Steven,这让我找到了我忘记的“依赖注入到.NET”一书中的相关部分。Mark称之为稳定依赖项和不稳定依赖项,我将添加另一个更详细的答案…@cedd:请注意,稳定依赖项和不稳定依赖项与可注入依赖项和可更新依赖项并不完全相同,因为稳定依赖项(例如来自第三方框架的类型)仍然可以是可注入依赖项。不过,稳定和不稳定之间的区别是非常有用的。