如何为工厂类创建的类提供依赖关系



假设我有一个名为ICustomer的接口,它定义了一个方法startProcessing():

interface ICustomer
{
void startProcessing(byte[] data);
}

现在,我有多个具体的类,比如ProductA_UserProductB_User。每个都有不同的属性,但它们都实现了ICustomer,因为它们都是客户:

class ProductA_User : ICustomer
{
string _name;
IRepository _repo;
public ProductA_User(string name)
{
_name = name;
}

public void startProcessing(byte[] data)
{
Console.WriteLine(_name);
var temp = _repo.Get<VModel>(filter: x.CName == _name).ToList();
}
}
class ProductB_User : ICustomer
{
public void startProcessing(byte[] data)
{
throw new System.NotImplementedException();
}
}

我正在调用一个名为MemberFactory的工厂类中的共享方法,并基于productType创建对象。

enum ProductTypeEnum { ProductA, ProductB }
class MemberFactory
{
ICustomer Create(ProductTypeEnum productType)
{
switch (productType)
{
case ProductTypeEnum.ProductA: return new ProductA_User("Steve");
case ProductTypeEnum.ProductB: return new ProductB_User();
default: return null;
}
}
}

我把它作为枚举的参数。由于每个具体类都不同,但实现了ICustomer,所以我能够返回一个实现ICustomer的实例。在ProductA_User()中,我试图注入_repo,它只是EF回购。

我该怎么办?我不想传递额外的参数(_repo)来创建类的对象。我怎样才能给我的concreate类注射?

某个地方有一个类需要ICustomer。您不希望该类了解ICustomer的任何实现,所以您使用的是MemberFactory

但是,如果需要ICustomer的类必须创建MemberFactory并像IRepository一样向其传递参数,那么您又回到了同样的问题。需要ICustomer的类不应该知道ICustomer的某些实现需要IRepository

对此有很多方法。我会选择一个简单直接的。

首先,为MemberFactory:创建一个接口

interface IMemberFactory
{
ICustomer Create(ProductTypeEnum productType)
}

更改MemberFactory的声明,使其实现接口:

class MemberFactory : IMemberFactory

无论在哪里注入MemberFactory,都应注入IMemberFactory。现在,依赖于IMemberFactory的类对其实现一无所知。它只知道它有一个IMemberFactory并调用它的Create方法。

然后,将IRepository注入到实现中,MemberFactory

class MemberFactory
{
private readonly IRepository _repository;
public MemberFactory(IRepository repository)
{
_repository = repository;
}
ICustomer Create(ProductTypeEnum productType)
{
switch (productType)
{
case ProductTypeEnum.ProductA: return new ProductA_User("Steve");
case ProductTypeEnum.ProductB: return new ProductB_User();
default: return null;
}
}
}

现在,如果MemberFactory需要一个IRepository来创建某些类型的ICustomer,那么它就有一个。这并不完美。如果我们以这种方式添加越来越多的依赖项,它可能会失控。但这只是一个开始。

然后,无论什么类型需要IMemberFactory来创建ICustomer,都要将IMemberFactory注入:

class SomeClassThatNeedsMemberFactory
{
private readonly IMemberFactory _memberFactory;
public SomeClassThatNeedsMemberFactory(IMemberFactory memberFactory)
{
_memberFactory = memberFactory;
}
}

现在每个类都注入了依赖项。因此,类不负责创建自己的依赖项。这意味着它对依赖关系的具体实现一无所知。SomeClassThatNeedsMemberFactory不知道具体的实现可能需要IRepository。它只知道IMemberFactory的接口。

这是依赖注入的重要组成部分。现在,如果我们更改IMemberFactory的实现,它的使用者不需要知道它,他们不知道传递给它的构造函数的是什么。

它还使每个类更容易测试。如果您正在测试SomeClassThatNeedsMemberFactory,则可以模拟IRespository


我还没有提到依赖注入/IoC容器,因为你没有问过它们,而且它们实际上不是依赖注入概念的核心。依赖项注入是关于构造类或方法,使它们接收依赖项,而不是创建它们——所有这些都是上面提到的。容器只是帮助我们管理所有这些。

假设我们使用的是IServiceCollection/IServiceProvider,这是目前.NET应用程序的默认容器。

如果我们在web应用程序的Startup类中工作,或者在其他应用程序类型中使用类似的类,我们就可以做到这一点。

void ConfigureServices(IServiceCollection services)
{
services.AddScoped<SomeClassThatNeedsMemberFactory>();
services.AddScoped<IMemberFactory, MemberFactory>();
services.AddScoped<IRepository, SomeConcreteRepository>();
}

这告诉服务集合

  • 我们将要求它创建SomeClassThatNeedsMemberFactory的实例
  • 如果要创建任何需要IMemberFactory实例的内容,请创建MemberFactory实例
  • 如果它正在创建任何需要IRepository实例的内容,请使用SomeConcreteRepository

现在假设应用程序需要创建Web API控制器的实例,并且我们已经注入了该控制器的SomeClassThatNeedsMemberFactory。服务提供商(依赖注入/IoC容器)会说

  • 我需要创建一个FooController的实例。构造函数说它需要一个SomeClassThatNeedsMemberFactory的实例,所以我将创建其中一个
  • 等等,SomeClassThatNeedsMemberFactory的构造函数需要一个IMemberFactory的实例。当我被要求IMemberFactory时,我使用MemberFactory,所以我将创建其中一个
  • 等等,MemberFactory的构造函数需要一个IRepository的实例。我将创建一个SomeConcreteRepository的实例

只要我们告诉它要使用什么类型,它就可以创建复杂的对象,其中依赖项具有需要更多依赖项的依赖项,等等。但我们不必为此考虑太多。我们可以一次只看一个类,并在编写、处理或测试时注意它需要什么依赖关系

这就是为什么容器如此受欢迎。没有他们,我们可以做到这一切,但这更难。然而,它们并不是依赖注入的全部内容。他们只是启用它。

最新更新