手作業による依存性注入は、合成および多型のより良い代替手段ですか?


13

まず、私は初心者レベルのプログラマーです。実際、私は夏の最後の絶頂プロジェクトでASの学位を取得しています。私の新しい仕事では、私がやるべきプロジェクトがないとき(彼らはチームにさらに新しい採用をするのを待っています)、私は待っている間に読んで学ぶための本を与えられました-いくつかの教科書、他のそれほど多くはありません(コード完了など)。これらの本を読んだ後、できる限り多くのことを学ぶためにインターネットに目を向け、SOLIDとDIについて学び始めました(Liskovの代替原理についてはいくらか話しましたが、SOLIDのアイデアについてはあまり話しませんでした)。それで、私が学んだように、私はよりよく学ぶために座って、DIを手動で利用するためのコードを書き始めました(開発コンピューターにはDIフレームワークはありません)。

私がやっているように、それは馴染みのあることに気づきます...そして、ポリモーフィズムを使った抽象クラスの構成を使って過去にやった仕事に非常に似ているようです。ここに大きな画像がありませんか?DIについて(少なくとも手で)それを超える何かがありますか?再コンパイルすることなく物事を変更する限り、いくつかの大きな利点を持つDIフレームワークのコードに設定がない可能性を理解していますが、手動で行う場合、上記と異なるかどうかはわかりません...これに関するいくつかの洞察は非常に役立つでしょう!

回答:


21

DIの基本的な考え方は、依存関係を外部からプルするのではなく、単純に依存関係をオブジェクトにプッシュすることです。これは、以前は「制御の反転」とも呼ばれていました。これにより、依存関係をより良く制御できます。最後になりますが、ユニットテストが簡単なコードを作成できます。

DIフレームワークはこのアイデアの上にのみ構築され、(部分的に)オブジェクトの依存関係をワイヤリングする際の退屈な部分を自動化します。それ以外の場合、手作業で行う場合は、より大きなプロジェクトで大量のコードが必要になる場合があります。

外部構成ファイルとは別に、依存関係を定義するために、最近ではJavaやC#などの言語でコード注釈を使用することもできます。これらは両方の長所をもたらす可能性があります。つまり、宣言的なスタイルで依存関係を配線しますが、論理的に属するコード自体の中にあります。私にとっては、再コンパイルすることなく依存関係を変更する可能性は、実際の生活ではまれに行われるため(特別な場合を除き)、それほど価値はありませんが、コード内で定義されたクラスおよびオブジェクトから依存関係をしばしば人工的に分離します。

タイトルの質問に戻ると、DIは構成や多態性に代わるものではありません。結局、これら2つによって可能になります。


1
依存性注入(DI)は、制御の反転(IoC)の形式です。
マシューフリン

@MatthewFlynn、確かに。参照:martinfowler.com/articles/injection.html
ペテル

1
それが私の参考です。彼は、コントロールの反転を行う新しい「軽量コンテナー」について話します。これは、UIイベントリスナーがIoCの形式であるため、すでに一般的なものでした。彼は、Springや他のIoCコンテナが依存性注入として行うオブジェクトバインディングをダビングして、他の形式のInversion of Controlと区別します。
マシューフリン

おっと-「本当に」見逃した。あなたは私に矛盾していると思いました...ごめんなさい。
マシューフリン

最後の段落で少し気分が良くなります。私が小さな学習プロジェクトに取り組んでいる間、私は自分自身に「これはポリモーフィズムのように感じます」と言い続けました。残念ながら、私の仕事の.Netとc#は恐ろしく古くなっていますが、調べてみると、Unityは組み込みのc#フレームワークですか?
ドレイククラリス

22

私がこのトピックについて読んだ中で最高の記事は、James Shoreの記事でした。抽象化とポリモーフィズムの一環として、私は長年にわたって「手作業によるDI」を行ってきました。ですから、私がプロの世界に入り、その用語が放り出されているのを聞き続けた後、私はその言葉意味するべきだと思ったものと実際に意味するものとの間に大きな隔たりがありました:

「依存性注入」は、5セントの概念を表す25ドルの用語です。

これはShoreの投稿からのもので、すべてをクリアしてくれました。例えば:

与えられた

class Engine {public abstract void start()}
class V8 extends Engine {...}
class V6 extends Engine {...}

書く代わりに:

class Car
{
    private Engine engine;
    public Car()
    {
        this.engine = new V6();
    }

    public void start()
    {
        this.engine.start();
    }
}

あなたは次のようなものを書きます:

class Car
{
    private Engine engine;
    public Car(Engine a)
    {
        this.engine = a;
    }

    public void start()
    {
        this.engine.start();
    }
}

...

Car F = new Car(new V8());

これにより、Carインスタンスが特定のEngine詳細を処理する必要がなくなります。車にはエンジンが必要なだけで、基本的なエンジン機能を実装している限り、どのエンジンでもかまいません。つまり、Carクラスは特定の実装依存関係に関連付けられていません。潜在的に実行時に、他の場所に「注入」されます。

この特定のCarの例では、「コンストラクターインジェクション」と呼ばれるDIのサブタイプを使用しています。これは、依存関係がコンストラクター引数として渡されたことを意味します。setEngine(Engine a)「セッターインジェクション」などの方法を使用することもできますが、これらのサブタイプは私にとってはつまらないものです。

しかし、もう少し多くのDIフレームワークは、これらのより抽象的に参照されたものを互いに結び付けるボイラープレートを提供します。

それでおしまい。


0

私は過去数年でDIを使い始めたばかりなので専門家ではありませんが、気づいたDIコンテナの有用なテーマ/機能のいくつかは(私は合成/多型の製品とは考えていません) (しかし、私はそれに関して訂正されるかもしれません):

  • オブジェクト作成の中央ハブ
  • スレッドごとにシングルトンを提供します
  • 傍受などのアスペクト指向技術

0

DIとは別に、ルートアプリケーションに(XMLを使用して構成する代わりに)クラス構成構成があります。特に大規模なプロジェクトの場合、クラス構成の構成を片付けることはできますが、DIまたはIoCフレームワークは必要ありません。これは、DIフレームワークには通常、クラス構成の構成に役立つ自動配線などの追加機能を実装するコンテナが付属しているためです。このトピックに関する私の理解を引き出すために、私のブログエントリを読むことができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.