9

私は依存性注入について学ぶ旅を始めています。DI を使用することをお勧めする理由の 1 つは、DI を使用すると依存関係が明示的に指定され、コードがより明確になることです。

インターフェイスが多用されていることにも気付きましたが、デフォルト コンストラクターを指定するためだけに抽象クラスを使用しない理由を知りたいですか?

もちろん、抽象クラスに実装を含めることはできません。

これはありませんか:

abstract class FooBase
{
    protected IBar _bar;

    FooBase(IBar bar)
    {
        _bar = bar;
    }

    abstract void DoSomething();
    abstract void DoSomethingElse();
}

FooBase オブジェクトの依存関係がそれ以上のものであることをより明確に示します。

interface IFoo
{
    IBar Bar { get; }

    void DoSomething();
    void DoSomethingElse();
}

?

私はこのコンセプト全体に慣れていないので、親切にしてください:)

4

3 に答える 3

6

技術的な理由の 1 つ - 多重継承のない言語 (Java/C#) で特定の親クラスを強制すると、「インターフェース」の実装の自由が大幅に制限されます。

「インターフェイス」という言葉の背後には 2 つの概念が隠されていることに注意してください。これにより、C# での推論が難しくなっています。

  • 「インターフェース」および抽象的な概念: オブジェクトと対話するための明確に定義された一連のプロパティ/メソッド。オブジェクトを操作するための契約。
  • 特定の言語 (C#/Java) での型としての「インターフェイス」 - 特定の言語でのコントラクトの表現の 1 つ。

抽象/具象クラスを使用してコントラクトを表すことができますが、C# でコントラクトの実装者に制限を課します。

他の一部の言語 (C++ など) にはそのような制限がなく、抽象クラスが適切なオプションです。他の言語 (つまり「ダックタイプ」の JavaScript) には、そのようなクラス/インターフェースの区別はありませんが、オブジェクトとの「コントラクト」を持つことはできます。

サンプル:

C# でこの制限を自分で実行する必要がある場合に、より多くのコンテキストを提供するには: DI は一般的に、何らかの形式の TDD と共に、または少なくとも基本的な単体テストと共に使用されます。したがって、DI の抽象基本クラスを使用するコードとテストをいくつか作成してみます。

abstract class Duck { 
  abstract void Quack();
}
class ConcreteDuck : Duck {...}

テストを書くことにした場合、オブジェクトをモックするのに役立つテスト クラスが既にあるかもしれません (既存のものを一度も使用していない場合)。

class MockBase {...}

class MockDuck : MockBase,?????? // Can't use Duck and MockBase together...
于 2012-07-19T21:26:34.350 に答える
5

インターフェイスはコントラクトを定義します。Abstract基本クラスは動作を定義します。

基本的に、複数のインターフェイスを実装する単一のクラスを提供できます。これにより、複数のクラスに注入できますが、(少なくともC#では)単一の抽象基本クラスしかありません。

コンテナー(せいぜいコンポジションルート)に型を登録するポイントを検討し、依存関係(コンストラクターまたはプロパティ)を解決するポイントを検討します。

このSOは、インターフェイスと基本クラスのSOに関するいくつかの側面をカバーします。

于 2012-07-19T21:31:27.623 に答える
1

.NETでは、継承は1つだけです。これが当てはまる言語/フレームワークでは、抽象化として抽象クラスを使用することを選択すると、「基本クラスを焼き付ける」可能性があります。

これは、抽象化の実装者に単一のクラスからの継承を強制することを意味します。そうすることを強制すると、実装が何であるかによっては、深刻な不便を招く可能性があります。

抽象クラスがあるとしましょうContract。誰かが(継承者の)メソッドBaseのみを公開する、使用したい独自のクラスを持っている場合。protected

メソッドはであるため、カプセル化(フィールドに格納されたprotectedインスタンス)を使用して、抽象化実装のメソッドにアクセスすることはできません。BaseBase

さらに悪いことに、変更するためのアクセス権がない場合はBase、いくつかの非常に醜い回避策(つまり、Reflection)に頼らなければならない可能性があります。

とは言うものの、インターフェースを使用すると、実装者に継承元の選択肢を提供し、オプションを制限しません。

表示される典型的なパターンは、常に契約用のインターフェースを提供し、そのインターフェースに対してコンシューマーをコーディングすることです。また、便宜上人々派生する可能性のある機能を提供する抽象基本クラスを提供しますが、から派生する義務はありません。

また、この機能を簡単にカプセル化できるものの形で提供できる場合(上記の条件の場合)、さらに最適になります(公開するインスタンスを呼び出すだけの抽象クラスがあります)。メソッド)。

于 2012-07-19T21:48:06.290 に答える