7

パブリック型のコレクションを消費者に提供するライブラリを作成しています。

このライブラリの依存性注入に適した型を作成したいと考えています。つまり、すべてのクラスには、初期化されるオブジェクトのすべての依存関係を指定できるコンストラクターが必要です。また、ライブラリが構成よりも規則に従うことも望んでいます。これは、消費者がデフォルトの動作を望む場合、パラメーターなしのコンストラクターを使用することができ、オブジェクトは何らかの方法でそれ自体の依存関係を構築することを意味します。

例 (C#):

public class Samurai {

    private readonly IWeapon _weapon;

    // consumers will use this constructor most of the time
    public Samurai() {
        _weapon = ??? // get an instance of the default weapon somehow
    }

    // consumers will use this constructor if they want to explicitly
    //   configure dependencies for this instance
    public Samurai(IWeapon weapon) {
        _weapon = weapon;
    }
}

私の最初の解決策は、サービス ロケーター パターンを使用することです。

コードは次のようになります。

...
public Samurai() {
    _weapon = ServiceLocator.Instance.Get<IWeapon>();
}
...

しかし、これには問題があります。Service locator はアンチパターン (リンク) としてフラグが立てられており、私はこれらの議論に完全に同意します。一方、Martin Fowler は、まさにこの状況 (ライブラリ プロジェクト) でサービス ロケーター パターンを使用することを提唱しています (リンク)。サービスロケーターが本当に悪い考えであることが判明した後、ライブラリを書き直す必要がないように注意したいと思います。

結論として、このシナリオではサービスロケータは問題ないと思いますか? まったく別の方法で問題を解決する必要がありますか? どんな考えでも大歓迎です...

4

3 に答える 3

4

DIコンテナーを使用していないユーザーの作業を楽にしたい場合は、次のDefaultsようなメソッドを持つ専用クラスを介してデフォルトのインスタンスを提供できます。

public virtual Samurai CreateDefaultSamurai()
{
   return new Samurai(CreateDefaultWeapon());
}

public virtual IWeapon CreateDefaultWeapon()
{
   return new Shuriken();
}

このようにして、デフォルトのコンストラクターでクラス自体を汚染する必要がなくなり、ユーザーがこれらのデフォルトのコンストラクターを意図せずに使用するリスクがなくなります。

于 2012-03-29T09:51:42.810 に答える
1

特定のプロバイダーを注入する代替手段があります。たとえば、WeaponProviderあなたのクラスに a を入れて、ルックアップを実行できるようにします。

public interface IWeaponProvider
{
    IWeapon GetWeapon();
}

public class Samurai
{
    private readonly IWeapon _weapon;

    public Samurai(IWeaponProvider provider)
    {
        _weapon = provider.GetWeapon();
    }
}

これで、武器にローカルのデフォルト プロバイダーを提供できるようになりました。

public class DefaultWeaponProvider : IWeaponProvider
{
    public IWeapon GetWeapon()
    {
        return new Sword();
    }
}

また、これはローカルの既定値であるため (別のアセンブリからのものとは対照的に、「ろくでなしの注入」ではありません)、Samurai クラスの一部としても使用できます。

public class Samurai
{
    private readonly IWeapon _weapon;

    public Samurai() : this(new DefaultWeaponProvider())
    {
    }

    public Samurai(IWeaponProvider provider)
    {
        _weapon = provider.GetWeapon();
    }
}
于 2012-03-28T23:19:21.033 に答える