IOC / DI有2个实现相同接口的类

时间:2012-07-04 17:10:56

标签: c# .net design-patterns dependency-injection inversion-of-control

我对实现相同接口和依赖注入的2个类的场景感到困惑。

public interface ISomething
{
  void DoSomething();
}

public class SomethingA : ISomething
{
  public void DoSomething()
  {

  }
}

public class SomethingAB : ISomething
{
  public void DoSomething()
  {

  }
}

public class Different
{
  private ISomething ThisSomething;

  public Different(ISomething Something)
  {  
    ThisSomething = Something;
  }
}

我见过网上的例子说这是有效的,但你一次只能使用一个班级。因此,如果应用程序在SiteA运行,您告诉您的IOC使用SomethingA,但如果它在SiteB,您告诉它使用SomethingAB。

因此,有一个应用程序有2个类实现1个接口,并尝试使用这两个类,这被认为是不好的做法吗?如果不是你怎么告诉国际奥委会在相关情况下使用哪个班级?

更新:为了更好地解释,我将使用Ninject的例子:

public class Samurai 
{
    private IWeapon Weapon;

    public Samurai(IWeapon weapon) 
    {
        this.Weapon = weapon;
    }
}

public class Sword : IWeapon
{
...
}

public class Gun : IWeapon
{
...
}

public class WarriorModule : NinjectModule
{
    public override void Load() 
    {
        this.Bind<IWeapon>().To<Sword>();
        this.Bind<IWeapon>().To<Gun>();  //Just an example
    }
}

所以现在你有两个使用IWeapon的类。根据您应用中的某些内容或背景,您希望Samurai有时会使用剑或在其他点使用枪。你是怎么做到这一点的?你如何处理“if”场景?

3 个答案:

答案 0 :(得分:13)

我不认为这在一般情况下是不好的做法。在某些情况下,您可能需要在同一个应用程序中使用相同接口的不同实现,并且基于上下文使用一个或另一个实现

至于如何配置你的DI以启用这种情况,当然,它将取决于你的DI :-)有些人可能不支持它,其他人可能不支持,其他人可能部分支持它等等。

例如,使用Ninject,您可以拥有以下类:

public interface ISomething
{
}

public class SomethingA : ISomething
{
}

public class SomethingB : ISomething
{
}

public class Foo
{
    public Foo(ISomething something)
    {
        Console.WriteLine(something);
    }
}

public class Bar
{
    public Bar(ISomething something)
    {
        Console.WriteLine(something);
    }
}

然后在配置内核时使用命名绑定:

// We create the kernel that will be used to provide instances when required
var kernel = new StandardKernel();

// Declare 2 named implementations of the same interface
kernel.Bind<ISomething>().To<SomethingA>().Named("somethingA");
kernel.Bind<ISomething>().To<SomethingB>().Named("somethingB");

// inject SomethingA into Foo's constructor
kernel.Bind<Foo>().ToSelf().WithConstructorArgument(
    "something", ctx => ctx.Kernel.Get<ISomething>("somethingA")
);

// inject SomethingB into Bar's constructor
kernel.Bind<Bar>().ToSelf().WithConstructorArgument(
    "something", ctx => ctx.Kernel.Get<ISomething>("somethingB")
);

现在,当您请求Foo的实例时,它会将SomethingA注入其构造函数中,当您请求Bar的实例时,它会向其注入SomethingB

var foo = kernel.Get<Foo>();
var bar = kernel.Get<Bar>();

答案 1 :(得分:-1)

我和Unity一起工作并且在这种背景下出现问题,我认为感兴趣在于包之间的弱耦合,即类,改变服务或进入点的能力是ioc的结果。

ioc提供了服务使用的灵活性,或者从服务实现相同接口的时间开始,

如果使用服务A服务B和服务在服务包A中,包B在B中。 包A没有对包b的引用,但是服务A在包含接口的包上有引用。 因此,我们得出结论,我们在包A和包b之间存在弱耦合。

答案 2 :(得分:-1)

将多个实现映射到同一个接口并不是一种非常糟糕的做法,但这并不是他最常用的用法模式。

您没有指定特定的DI工具,但如果您使用Unity,则可以使用命名实例执行此操作。见这里:Unity - how to use multiple mappings for the same type and inject into an object