我对实现相同接口和依赖注入的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”场景?
答案 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