11

我对实现相同接口和依赖注入的 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
    }
}

所以现在你有 2 个使用 IWeapon 的类。根据您的应用程序中的某些内容或上下文,您希望武士有时拥有一把剑或在其他地方拥有一把枪。你如何做到这一点?你如何处理那种“如果”的情况?

4

3 回答 3

14

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

至于如何配置您的 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>();
于 2012-07-04T17:29:41.600 回答
-1

在这种情况下,我与 Unity 和 spring 一起工作,我认为兴趣在于包之间的弱耦合,即类,更改服务或入口点的能力是 ioc 的结果。

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

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

于 2012-07-04T17:18:38.353 回答
-1

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

您没有指定特定的 DI 工具,但如果您使用 Unity,则可以使用命名实例执行此操作。请参见此处:Unity - 如何为同一类型使用多个映射并注入到对象中

于 2012-07-04T17:30:54.677 回答