9

特定のクラスではなくコントラクトをプログラミングすると同時に、IoC/依存性注入を使用することに同意しようとしています。私が抱えているジレンマは、次の間の緊張です。

  1. Do program to interfaces to IoC : インターフェイスに大きく依存する IoC から始めました。Spring のサンプル プロジェクトから判断すると、IoC とのコントラクトに合わせてプログラミングする場合は、インターフェースが最適です。

  2. ( ... 一般的には抽象クラスが好まれますが、インターフェイスの主な欠点は、API の進化を可能にすることに関して、クラスよりもはるかに柔軟性が低いことです)

  3. コンストラクターを介してクラスの依存関係を明示的にする 私の直感では、クラスのコンストラクターに依存関係を渡すことは、プログラミングの良い実践方法であるということです。実際、これ依存性注入です。

  4. ...インターフェース/抽象クラスでコンストラクター署名を強制できないことを除いて:インターフェースも抽象クラスもコンストラクター署名を定義することを許可しません(簡単/エレガントに)フレームワーク設計ガイドラインのセクション 4.4 も参照してください:抽象型でパブリックまたは保護された内部コンストラクターを定義しないでください。... コンストラクターは、ユーザーが型のインスタンスを作成する必要がある場合にのみパブリックにする必要があります。

この質問は、以前のスタックオーバーフローの質問に関連しています:コンストラクターの署名を定義するインターフェイス?

しかし、私の質問は次のとおりです。

上記の質問で尋ねたように、C# インターフェイス/抽象クラスではコンストラクターを定義できないため、実用的なレベルでは次のようになります。

これを、コンストラクターを介して依存関係を渡すという賢明な慣行とどのように調和させますか?

編集:答えてくれてありがとう。この場合、どうすればよいかについての洞察を期待しています。コンストラクター引数を使用しないだけですか? 依存関係を取るある種の Init() メソッドを使用しますか? Edit2:素晴らしい回答をありがとう、とても役に立ちました。

4

3 に答える 3

8

これは(構成された)例で説明する方が簡単だといつも思います...

ICustomerRepository インターフェイス、IShoppingCartRepository インターフェイス、および ICheckout インターフェイスがあるとします。これらのインターフェイス (CustomerRepository、ShoppingCartRepository、および CheckoutService) の具体的な実装があります。

CheckoutService 具象クラスには、ICustomerRepository と IShoppingCartRepository を受け取るコンストラクターがあります。

public CheckoutService(ICustomerRepository customerRepository, IShoppingCartRepository shoppingCartRepository)
{
  // Set fields for use in some methods later...
  _customerRepository = customerRepository;
  _shoppingCartRepository = shoppingCartRepository;
}

次に、ICheckoutService の実装でなんらかの作業を行う必要がある場合は、IoC コンテナーに各インターフェイス タイプに使用する具象クラスを指定し、ICheckoutService をビルドするように依頼します。IoC コンテナーが移動してクラスを構築し、CheckoutService のコンストラクターに正しい具象クラスを挿入します。また、ここでクラス階層のずっと下まで依存関係を構築します。たとえば、ShoppingCartRepository がコンストラクターで IDatabaseSession インターフェイスを受け取る場合、使用する具象クラスを指定している限り、IoC コンテナーもその依存関係を注入します。あなたの IDatabaseService のために。

(たとえば) StructureMapを IoC コンテナーとして構成するときに使用できるコードを次に示します (このコードは通常、アプリの起動時に呼び出されます)。

public class AppRegistry : Registry
{
  public AppRegistry()
  {
    ForRequestedType<ICheckoutService>().TheDefaultIsConcreteType<CheckoutService>();
    ForRequestedType<ICustomerRepository>().TheDefaultIsConcreteType<CustomerRepository>();
    // etc...
  }
}

次に、ICheckoutService のインスタンスを作成してすぐに使用できるようにするには、すべての依存関係をコンストラクターに渡します。次のようなものを使用します。

var checkoutService = ObjectFactory.GetInstance<ICheckoutService>();

それが理にかなっていることを願っています!

于 2009-04-16T22:26:26.363 に答える
1

IoC コンテナーは、渡す対象がインターフェイスであっても、具象型からオブジェクトを構築する必要があります。コンストラクターは動作または状態のコントラクトではないため、インターフェイスに属したり、抽象クラスのパブリック メンバーとして属したりしません。

コンストラクターは実装の詳細であるため、その定義を具象クラスから分離する必要はありません。

于 2009-04-16T15:06:53.343 に答える
0

インターフェイスでコンストラクター シグネチャを定義することはできません。インターフェイスは実装の構築方法を強制するべきではないため、とにかく意味がありません。

ただし、抽象クラスは実際にコンストラクターを持つことができます。public コンストラクターも意味をなさないため、保護する必要があります。それらは具体的なサブクラスによってのみ呼び出されるべきです。

IoC の原則では、クラス A にクラス B を認識させてインスタンス化する代わりに、IB への参照を A のコンストラクターに渡す必要があります。そうすれば、A はクラス B について知る必要がないため、クラス B を簡単に置き換えることができます。 IBの他の実装と。

クラス B の既にインスタンス化されたオブジェクトを渡すため、IB インターフェイスはコンストラクター シグネチャを持つ必要はありません。

于 2009-04-16T15:07:58.097 に答える