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;
  }
}

オンラインの例では、これは有効であると言われていますが、一度に使用できるクラスは1つだけです。したがって、アプリがSiteAで実行されている場合は、IOCにSomethingAを使用するように指示しますが、SiteBで実行されている場合は、SomethingABを使用するように指示します。

したがって、1つのインターフェイスを実装する2つのクラスを持つ1つのアプリを作成し、両方のクラスを使用しようとするのは悪い習慣と見なされますか?そうでない場合、関連する状況でどのクラスを使用するかをIOCにどのように伝えますか?

更新:それをよりよく説明するために、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を使用する2つのクラスができました。アプリ内の何かやコンテキストに応じて、サムライに時々剣を持たせたり、他の場所に銃を持たせたりします。どうやってこれを実現しますか?その「if」シナリオをどのように処理しますか?

4

3 に答える 3

14

これは一般的なケースでは悪い習慣ではないと思います。同じアプリケーション内で同じインターフェースの異なる実装が必要になる可能性があり、コンテキストに基づいて1つまたは別の実装を使用する場合があります

このシナリオを有効にするために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 に答える