依存性注入コンテナの利点は何ですか?


104

依存性注入自体の利点を理解しています。たとえば、Springを例にとってみましょう。また、AOPやさまざまな種類のヘルパーなど、他のSpring機能の利点についても理解しています。次のようなXML構成の利点は何でしょうか。

<bean id="Mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="John" class="foo.bar.Male">
  <property name="girlfriend" ref="Mary"/>
</bean>

次のようなプレーンな古いJavaコードと比較して:

Female mary = new Female();
mary.setAge(23);
Male john = new Male();
john.setGirlfriend(mary);

これはデバッグがより簡単で、コンパイル時間をチェックし、Javaだけを知っている人なら誰でも理解できます。それでは、依存性注入フレームワークの主な目的は何ですか?(またはその利点を示すコードの一部)


更新:の
場合

IService myService;// ...
public void doSomething() {  
  myService.fetchData();
}

IoCフレームワークは、複数ある場合に、注入するmyServiceの実装をどのように推測できますか?特定のインターフェイスの実装が1つしかなく、IoCコンテナーにそれを使用するように自動的に決定させると、2番目の実装が表示された後に壊れます。また、インターフェースの実装が意図的に1つしかない場合は、それを注入する必要はありません。

IoCのメリットを示す小さな構成を見るのは本当に興味深いでしょう。私はしばらくSpringを使用しており、そのような例を提供することはできません。また、休止状態、dwr、および私が使用するその他のフレームワークの利点を示す1行を表示できます。


更新2:
IoC構成は再コンパイルせずに変更できることを理解しています。本当にいいアイデアですか?再コンパイルせずにDB資格情報を変更したい場合は理解できます-彼は開発者ではない可能性があります。実際に、開発者以外の誰かがIoC構成を変更する頻度はどれくらいですか?開発者にとって、構成を変更する代わりにその特定のクラスを再コンパイルする努力はないと思います。そして、非開発者にとっては、おそらく彼の人生をより簡単にし、いくつかのより単純な設定ファイルを提供したいと思うでしょう。


更新3:

インターフェースとその具体的な実装間のマッピングの外部構成

それを外部のものにすることで何が良いのですか?すべてのコードを外部にする必要はありませんが、ClassName.java.txtファイルに配置して、オンザフライで手動で読み取り、コンパイルすることはできますが、再コンパイルは不要です。コンパイルを避けるべきなのはなぜですか?

手続き型コードではなく宣言的にマッピングを提供するため、コーディング時間を節約できます。

ときどき宣言的アプローチが時間を節約することを理解しています。たとえば、BeanプロパティとDB列の間のマッピングを一度だけ宣言し、HSQLに基づいてSQLをロード、保存、構築するときにhibernateがこのマッピングを使用します。これが宣言的なアプローチが機能する場所です。Spring(私の例では)の場合、宣言はより多くの行を持ち、対応するコードと同じ表現力を持っていました。そのような宣言がコードより短い場合の例があれば、私はそれを見たいです。

制御の原則の反転により、実際の実装を偽の実装に置き換えることができるため(SQLデータベースをメモリ内の実装に置き換えるなど)、ユニットテストが容易になります。

私は制御の利点の反転を理解しています(IoCはより一般的な-多くの種類の制御があり、そのうちの1つだけを反転しているため、ここで説明する設計パターンを依存性注入と呼びます-初期化の制御)。なぜ誰かがプログラミング言語以外のものを必要とするのかと尋ねていました。コードを使用して、実際の実装を偽の実装に確実に置き換えることができます。そして、このコードは構成と同じことを表現します-偽の値でフィールドを初期化するだけです。

mary = new FakeFemale();

DIのメリットは理解しています。同じことを行うコードの構成と比較して、外部XML構成によってどのような利点が追加されるのか理解できません。コンパイルは避けるべきだとは思いません。毎日コンパイルしていますが、まだ生きています。DIの構成は宣言型アプローチの悪い例だと思います。宣言は、1回宣言され、さまざまな方法で何度も使用される場合に役立ちます。Hibernatecfgのように、BeanプロパティとDB列の間のマッピングは、保存、ロード、検索クエリの構築などに使用されます。SpringDI構成は簡単に次のように変換できます。この質問の最初のように、コードを構成することはできませんか?そして、それはBeanの初期化にのみ使用されますね。これは、宣言的アプローチがここで何も追加しないことを意味しますか?

hibernateマッピングを宣言するときは、hibernateにいくつかの情報を提供するだけで、それに基づいて機能します-何をすべきかは指示しません。春の場合、私の宣言は春に正確に何をするように指示します-なぜそれを宣言するのですか、なぜそれをしないのですか?


最終更新:
皆さん、多くの回答が依存関係の注入について教えてくれています。問題は、コードを初期化する代わりにDI構成の目的についてです。コードを初期化する方が短くて明確であると思う傾向があります。私の質問に対して私がこれまでに得た唯一の答えは、構成が変更されたときに再コンパイルを回避することです。これは私にとって大きな秘密なので、別の質問を投稿する必要があると思います。この場合、コンパイルを回避する必要があるのはなぜですか。


21
最後に、誰かがこの質問をする勇気がありました。ツール/ IDEサポートを犠牲にする(または少なくとも低下させる)ことを犠牲にして実装が変更されたときに、実際に再コンパイルを避けたいのはなぜですか?
クリスチャンクラウザー2010

3
タイトルがおかしいようです。著者は、IOCコンテナーは問題ないと述べていますが、コードを介して構成するのではなく、XML構成を使用すると問題が発生するようです(そして十分に公正です)。「XMLやその他の非コードアプローチを使用してIOCコンテナーを構成する利点は何ですか?」
オリオンエドワーズ

私が提供した@Orionの例(男性および女性)は、IOCコンテナを必要としません。私はIOCで元気です。XMLを使用して構成されているかどうかに関係なく、コンテナーを使用することは依然として私にとって未解決の問題です。
Pavel Feldman

@Orion 2:ほとんどのプロジェクトで何らかの形式のIOCを使用していますが、変数割り当てコンテナーまたはIfステートメントコンテナーの利点と同じくらい、IOCコンテナーの利点を享受している言語もあります。私が取り組んでいるプロジェクトを再コンパイルし、dev / test / production初期化コードを便利に分離しても問題ありません。だから私にとってタイトルは結構です。
Pavel Feldman、2009

サンプルに問題があります。原則として、データではなくサービスを注入する
Jacek Cz

回答:


40

私自身、IoCを使用する(そして外部設定を使用する)主な理由の1つは、次の2つの領域にあります。

  • テスト中
  • 生産保守

テスト中

テストを3つのシナリオに分割した場合(大規模な開発ではこれはかなり普通のことです):

  1. ユニットテスト
  2. 統合テスト
  3. ブラックボックステスト

最後に行う2つのテストシナリオ(統合とブラックボックス)では、アプリケーションのどの部分も再コンパイルしません。

テストシナリオのいずれかで構成を変更する必要がある場合(つまり、別のコンポーネントを使用して銀行の統合を模倣するか、パフォーマンスの負荷をかける)、これは簡単に処理できます(これには、DI側の構成の利点があります) IoC。

さらに、アプリが複数のサイト(サーバーとコンポーネントの構成が異なる)で使用されている場合、またはライブ環境で構成が変更されている場合は、テストの後の段階を使用して、アプリがそれらの変更を処理することを確認できます。

製造

開発者は本番環境を制御できない(すべきでない)(特に、アプリが複数の顧客または別のサイトに配布されている場合)、これはIoCと外部構成の両方を使用する本当の利点です、開発者に戻ってテストすることなくライブ環境を微調整および調整するのはインフラストラクチャ/本番サポートの責任であるため(開発者がやりたいのはコンポーネントを移動するだけの場合はコストが高くなります)。

概要

IoCの外部構成が他の開発者以外の人にアプリケーションを構成する権限を与えることによる主な利点は、私の経験では、これは限られた一連の状況でのみ有用です。

  • アプリケーションは、環境が異なる複数のサイト/クライアントに配布されます。
  • 本番環境とセットアップに対する制限された開発制御/入力。
  • テストシナリオ。

実際に、環境を制御できる何かを開発している場合でも、それが実行されるようになる場合でも、時間の経過とともに、構成を変更する機能を他の誰かに与えるほうがよいことがわかりました。

  • 開発するときには、いつ変更されるのかわかりません(このアプリは非常に便利なので、会社が他の人に販売しています)。
  • 適切な構成モデルをセットアップして使用することで処理できた可能性のあるわずかな変更が要求されるたびにコードを変更することに行き詰まりたくありません。

注:アプリケーションとは完全なソリューション(実行可能ファイルだけでなく)を指すため、アプリケーションを実行するために必要なすべてのファイル


14

依存性注入は、オブジェクトの委任は通常、オブジェクトの継承よりも有用な設計パターンであるという観察にルーツを持つコーディングスタイルです(つまり、オブジェクトはオブジェクトの関係よりもオブジェクトの関係の方が便利です)。ただし、DIが機能するには、オブジェクトインターフェイスを作成するという、もう1つの要素が必要です。これら2つの強力な設計パターンを組み合わせると、ソフトウェアエンジニアは柔軟な疎結合コードを作成できることにすぐに気づき、依存性注入の概念が生まれました。ただし、DIが本当に普及したのは、特定の高水準言語でオブジェクトリフレクションが利用できるようになるまででした。反射コンポーネントは、今日のほとんどのコアです

言語は、通常のオブジェクト指向プログラミング手法と、オブジェクトインターフェイスおよびオブジェクトリフレクション(JavaやC#など)の両方を適切にサポートする必要があります。C ++システムでDIパターンを使用してプログラムを構築することはできますが、適切な言語内のリフレクションサポートがないため、アプリケーションサーバーや他のDIプラットフォームをサポートできず、DIパターンの表現力が制限されます。

DIパターンを使用して構築されたシステムの強み:

  1. 「依存」機能が明確に定義されたインターフェースに外挿されるため、DIコードは再利用がはるかに容易になり、適切なアプリケーションプラットフォームによって構成が処理される個別のオブジェクトを自由に他のオブジェクトにプラグインできます。
  2. DIコードはテストがはるかに簡単です。オブジェクトによって表現される機能は、アプリケーションロジックが期待するインターフェイスを実装する「モック」オブジェクトを作成することにより、ブラックボックスでテストできます。
  3. DIコードはより柔軟です。それは本質的に疎結合のコードです-極端です。これにより、プログラマは、オブジェクトの接続方法を、一方の端で必要なインターフェイスともう一方の端で表現されたインターフェイスのみに基づいて選択することができます。
  4. DIオブジェクトの外部(Xml)構成は、他のユーザーが予期しない方向でコードをカスタマイズできることを意味します。
  5. 外部設定は、オブジェクトの初期化とオブジェクトの相互依存管理のすべての問題をアプリケーションサーバーで処理できるという点で、懸念の分離パターンでもあります。
  6. DIパターンを使用するために外部構成は必要ないことに注意してください。単純な相互接続の場合、小さなビルダーオブジェクトで十分です。2つの間の柔軟性にはトレードオフがあります。ビルダーオブジェクトは、外部から見える構成ファイルほど柔軟なオプションではありません。DIシステムの開発者は、構成ファイルで表現されているオブジェクト構築に対する小規模で細かい制御によって混乱とメンテナンスコストが増大する可能性があることに注意しながら、利便性よりも柔軟性の利点を比較検討する必要があります。

間違いなくDIコードはより扱いにくいように思われますが、オブジェクトを構成するすべてのXMLファイルを他のオブジェクトに挿入することの欠点は難しいように見えます。しかし、これがDIシステムのポイントです。コードオブジェクトを一連の構成設定として混在させて照合する機能により、サードパーティのコードを使用して複雑なシステムを構築し、最小限のコーディングで済みます。

質問で提供された例は、適切に因数分解されたDIオブジェクトライブラリが提供できる表現力の表面に触れるだけです。いくつかの練習と多くの自己規律により、ほとんどのDI開業医は、アプリケーションコードの100%テストカバレッジを持つシステムを構築できることに気づきます。この一点だけでも異常です。これは、数百行のコードの小さなアプリケーションの100%テストカバレッジではなく、数十万行のコードで構成されるアプリケーションの100%テストカバレッジです。このレベルのテスト容易性を提供する他の設計パターンを説明することができなくなっています。

ほんの数十行のコードのアプリケーションは、いくつかのオブジェクトと一連のXML構成ファイルよりも理解しやすいという点で正しいです。ただし、最も強力な設計パターンと同様に、システムに新しい機能を追加し続けると、その効果が得られます。

つまり、大規模なDIベースのアプリケーションは、デバッグも理解も容易です。Xml構成は「コンパイル時チェック」されませんが、この作成者が認識しているすべてのアプリケーションサービスは、互換性のないインターフェイスを持つオブジェクトを別のオブジェクトに挿入しようとすると、開発者にエラーメッセージを提供します。そして、ほとんどは、すべての既知のオブジェクト構成をカバーする「チェック」機能を提供します。これは、注入されるオブジェクトAが、構成されたすべてのオブジェクト注入に対してオブジェクトBが必要とするインターフェイスを実装していることを確認することで、簡単かつ迅速に実行されます。


4
DIの利点を理解する。同じことを行うコードの構成と比較して、外部XML構成によってどのような利点が追加されるのか理解できません。あなたが言及した利点は、DI設計パターンによって提供されます。問題は、単純な初期化コードと比較したDI構成の利点についてでした。
Pavel Feldman、

>外部構成も分離です...構成の分離は良いDIの心臓部です。また、初期化コードを使用してドームを解除できます。コードの初期化と比較してcfgは何を追加しますか?私にとって、cfgの各行には対応する初期化コード行があるようです。
Pavel Feldman、

7

これはちょっとした質問ですが、膨大な量のxml構成が実際に多くの利益につながらないことに同意する傾向があります。高額なフレームワークを含め、アプリケーションの依存関係をできるだけ軽くすることが好きです。

コードを大幅に簡略化しますが、複雑さのオーバーヘッドがあり、問題の追跡がかなり困難になります(そのような問題を直接目にしてきましたが、Javaを扱う方がずっと快適です)。

私はそれが少しスタイルとあなたが快適であるものに依存すると思います...あなたはあなた自身のソリューションを飛ばして、それを裏返しに知るという利点を持っていますか、それとも構成が難しいときに証明されるかもしれない既存のソリューションに頼りますか? tちょうどいいですか?それはすべてトレードオフです。

ただし、XML構成はちょっとした不満です...私はそれを絶対に避けようとします。


5

コードをデータに変更できるときはいつでも、正しい方向に進んでいます。

何かをデータとしてコーディングすることは、コード自体がより一般的で再利用可能であることを意味します。また、正確に適合する言語でデータを指定できることも意味します。

また、XMLファイルをGUIや他のツールに読み込んで、実用的に操作することもできます。コード例でそれをどのように行いますか?

私は、ほとんどの人がコードとしてデータに実装するものを常にファクタリングしています。これにより、残っているコードがはるかにクリーンになります。メニューをデータとしてではなくコードで作成することは考えられません-ボイラープレートがあるため、コードでそれを行うのは明らかに間違っていることは明らかです。


理にかなっている、この観点ではそれについて考えていなかった
Pavel Feldman

7
繰り返しになりますが、多くの場合、人々は逆の方向に進み、ロジックをデータに入れます。つまり、アプリケーションを標準以下のプログラミング言語でコーディングすることになります
Casebash

@Casebashそれは興味深い視点です。例に驚くほど興味があります。データに移動できるものなら何でも役に立ちます。また、私があなたが言っていることだけを行うと、その言語はDSLであるため実際には改善されます。しかし、それでも、まったく新しい言語を作成することは深刻な正当化を必要とします。
ビルK

1
「いつでも、コードをデータに変更して、正しい方向に進んでいます。」ソフトコーディングアンチパターンへようこそ。
Raedwald

@Raedwaldあなたが話しているのは外部化であり、あなたが何をしているのか(そして無能な人がそれを試み、失敗し、それをアンチパターンと呼んだ理由)を知らない場合、それは本当に難しいかもしれません。 、注釈付きのほぼすべて、配列で初期化されるもの。最も優れたプログラミング構造は、コードの違いを分離し、残っているものを組み合わせて、グループ化および管理が容易なものでそれを推進する試みです。
Bill K

3

DIコンテナーを使用する理由は、単にゲッターとセッターである、コード内で事前に構成された10億のプロパティを持つ必要がないためです。これらすべてを新しいX()でハードコーディングしますか?もちろん、デフォルトを設定することもできますが、DIコンテナを使用すると、非常に簡単にシングルトンを作成でき、初期化などのさまざまなタスクではなく、コードの詳細に集中できます。

たとえば、Springを使用すると、InitializingBeanインターフェースを実装し、afterPropertiesSetメソッドを追加できます(コードをSpringに結合しないように「init-method」を指定することもできます)。これらのメソッドを使用すると、クラスインスタンスのフィールドとして指定されたインターフェイスが起動時に正しく構成されていることを確認でき、ゲッターとセッターをnullチェックする必要がなくなります(シングルトンがスレッドセーフのままであることを許可している場合) )。

さらに、DIコンテナを使用して複雑な初期化を行う方が、自分で行うよりもはるかに簡単です。たとえば、XFireの使用を支援します(CeltiXFireではなく、Java 1.4のみを使用します)。アプリはSpringを使用していましたが、残念ながらXFireのservices.xml設定メカニズムを使用していました。要素のコレクションで、インスタンスが1つ以上ではなく0つ以上であることを宣言する必要がある場合、この特定のサービス用に提供されているXFireコードの一部をオーバーライドする必要がありました。

Spring Beanスキーマには、特定のXFireデフォルトが定義されています。したがって、Springを使用してサービスを構成している場合は、Beanが使用されている可能性があります。代わりに、Beanを使用する代わりに、services.xmlファイルで特定のクラスのインスタンスを指定する必要がありました。これを行うには、コンストラクターを提供し、XFire構成で宣言された参照をセットアップする必要がありました。必要な実際の変更では、単一のクラスをオーバーロードする必要があります。

しかし、services.xmlファイルのおかげで、4つの新しいクラスを作成し、コンストラクターのSpring構成ファイルのデフォルトに従ってデフォルトを設定する必要がありました。Spring構成を使用できたとしたら、次のように述べたでしょう。

<bean id="base" parent="RootXFireBean">
    <property name="secondProperty" ref="secondBean" />
</bean>

<bean id="secondBean" parent="secondaryXFireBean">
    <property name="firstProperty" ref="thirdBean" />
</bean>

<bean id="thirdBean" parent="thirdXFireBean">
    <property name="secondProperty" ref="myNewBean" />
</bean>

<bean id="myNewBean" class="WowItsActuallyTheCodeThatChanged" />

代わりに、次のようになります。

public class TheFirstPointlessClass extends SomeXFireClass {
    public TheFirstPointlessClass() {
        setFirstProperty(new TheSecondPointlessClass());
        setSecondProperty(new TheThingThatWasHereBefore());
    }
}

public class TheSecondPointlessClass extends YetAnotherXFireClass {
    public TheSecondPointlessClass() {
        setFirstProperty(TheThirdPointlessClass());
    }
}

public class TheThirdPointlessClass extends GeeAnotherXFireClass {
    public TheThirdPointlessClass() {
        setFirstProperty(new AnotherThingThatWasHereBefore());
        setSecondProperty(new WowItsActuallyTheCodeThatChanged());
    }
}

public class WowItsActuallyTheCodeThatChanged extends TheXFireClassIActuallyCareAbout {
    public WowItsActuallyTheCodeThatChanged() {
    }

    public overrideTheMethod(Object[] arguments) {
        //Do overridden stuff
    }
}

したがって、最終的には、4つの追加の、ほとんど無意味なJavaクラスをコードベースに追加して、1つの追加のクラスといくつかの単純な依存関係コンテナ情報を実現するという効果を達成する必要がありました。これは「ルールを証明する例外」ではありません。これはルールです...コードがプロパティをすでにDIコンテナーで提供されており、特別な状況に合わせてプロパティを変更するだけの場合、コードの癖ははるかに明確になります。それはより頻繁に発生します。


3

あなたの答えがあります

各アプローチには明らかにトレードオフがありますが、外部化されたXML構成ファイルは、IDEではなくビルドシステムを使用してコードをコンパイルするエンタープライズ開発に役立ちます。ビルドシステムを使用して、特定の値をコードに挿入したい場合があります。たとえば、ビルドのバージョン(コンパイルするたびに手動で更新する必要がある場合がある)などです。ビルドシステムが一部のバージョン管理システムからコードをプルする場合、その痛みはさらに大きくなります。コンパイル時に単純な値を変更するには、ファイルを変更してコミットし、コンパイルして、変更するたびに元に戻す必要があります。これらは、バージョン管理にコミットしたい変更ではありません。

ビルドシステムと外部構成に関するその他の有用な使用例:

  • 異なるビルドの単一のコードベースにスタイル/スタイルシートを挿入する
  • 単一のコードベースに動的コンテンツの異なるセット(またはそれらへの参照)を挿入する
  • 異なるビルド/クライアントにローカリゼーションコンテキストを挿入する
  • WebサービスURIをバックアップサーバーに変更する(メインサーバーがダウンした場合)

更新:上記の例はすべて、必ずしもクラスへの依存関係を必要としないものに関するものでした。ただし、複雑なオブジェクトと自動化の両方が必要な場合は、次のように簡単に作成できます。

  • あなたのウェブサイトのトラフィックを監視するシステムがあったと想像してください。同時ユーザー数に応じて、ロギングメカニズムのオン/オフを切り替えます。おそらく、メカニズムがオフの間に、スタブオブジェクトがその場所に配置されます。
  • ユーザー数に応じて、参加者数に応じてP2Pを実行する機能を切り替えたいWeb会議システムがあるとします。

+1は、企業の側面を一番上に強調表示します。不十分に記述されたレガシーコードをテストすることは、時には1日中悪夢になることがあります。
Richard Le Mesurier、

2

構成で何かを変更するたびにコードを再コンパイルする必要はありません。プログラムの展開とメンテナンスを簡素化します。たとえば、構成ファイルを1回変更するだけで、あるコンポーネントを別のコンポーネントと交換できます。


展開?おそらく...展開のメンテナンス?おそらく...コードのメンテナンス?私はだめだと思う傾向があります...フレームワークを介したデバッグは大きな頭痛の種になる傾向があり、その点でpojoの方がはるかに扱いやすいです。
マイクストーン

1
マイク、私はコードについて何も言わなかった。XMLの構成が悪いことは誰でも知っています:)
aku

うーん..再コンパイルせずにコンポーネントを変更する頻度はどれくらいですか?誰かがDB資格情報を変更し、プログラムを再コンパイルしたくない場合は理解しています-彼はそれを開発した人ではない可能性があります。しかし、私はほとんど春の構成を変更し、開発者以外の人を想像することはできません
パヴェル・フェルドマン

通常、Pavelは、プログラムを数百のクライアントに展開する必要がある場合に発生します。このような状況では、製品の新しいバージョンをデプロイするよりも、構成を変更する方がはるかに簡単です。あなたはまさに開発者について言っています。通常、開発者は新しいcfgを作成し、管理者がそれをデプロイします。
aku

2

あなたはガールフレンドのための新しい実装を組み込むことができます。そのため、コードを再コンパイルせずに新しい女性を注入できます。

<bean id="jane" class="foo.bar.HotFemale">
  <property name="age" value="19"/>
</bean>
<bean id="mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="john" class="foo.bar.Male">
  <property name="girlfriend" ref="jane"/>
</bean>

(上記はFemaleとHot Femaleが同じGirlfFriendインターフェースを実装することを前提としています)


再コンパイルせずにロジックを変更することをお勧めします。
Pavel Feldman、

私は間違いなくHot Female jane = new HotFmale();を実行できます。jane.setAge(19); john.setGirlfriend(jane); 唯一の違いは、cfgは再コンパイルせずに変更できるということですか?春を議論するとき、それは一般的な答えのようです。なぜ?!コンパイルを避けるのはなぜ良いのですか?
Pavel Feldman、

まあ、私は女性オブジェクトをモックすることができるより良いコードをテストすることができます。
ポールウィラン

@Pavel Feldman:すでにクライアントでアプリをデプロイしている場合、これは簡単です。
AndreiRînea10年

1

.NETの世界では、ほとんどのIoCフレームワークがXMLとコードの両方の構成を提供します。

たとえば、StructureMapとNinjectは、流れるようなインターフェイスを使用してコンテナーを構成します。XML構成ファイルを使用する必要はなくなりました。.NETにも存在するSpringは、これまでのメインの構成インターフェースであるため、XMLファイルに大きく依存していますが、プログラムでコンテナーを構成することも可能です。


それが私が最終的にそれを使用することを意図したもののコードを使用できることは素晴らしいことです:)しかし、なぜそのようなことをするためにプログラミング言語以外のものも必要なのですか?
Pavel Feldman、

XMLを使用すると、プロジェクトを再コンパイルしなくても、ランタイムの変更、または少なくとも構成の変更が可能になるためだと思います。
Romain Verdier

1

部分的な構成を最終的な完全な構成組み合わせるのが容易。

たとえば、Webアプリケーションでは、モデル、ビュー、コントローラーは通常、個別の構成ファイルで指定されます。宣言的アプローチを使用すると、たとえば次のようにロードできます。

  UI-context.xml
  Model-context.xml
  Controller-context.xml

または、別のUIといくつかの追加のコントローラーでロードします。

  AlternateUI-context.xml
  Model-context.xml
  Controller-context.xml
  ControllerAdditions-context.xml

コードで同じことを行うには、部分的な構成を組み合わせるためのインフラストラクチャが必要です。コードで行うことは不可能ではありませんが、IoCフレームワークを使用する方が確かに簡単です。


1

多くの場合、重要なポイントは誰ですか、プログラムの作成後にが構成を変更するかです。コードでの構成では、それを変更する人は、元の作者が持っていたのと同じスキルとソースコードへのアクセス権を持っていると暗黙的に想定します。

プロダクションシステムでは、設定のサブセット(例では年齢)をXMLファイルに抽出し、システム管理者やサポート担当者がソースコードやその他の設定にフルパワーを与えずに値を変更できるようにすること、または単に複雑さからそれらを分離します。


それは妥当なポイントですが、スプリングの構成はしばしばかなり複雑になる傾向があります。年齢を変更するのは簡単ですが、sysadminは、完全に理解する必要のない大きなxmlファイルを処理する必要があります。Spring XML構成よりも、さらに単純なものに構成することになっている部分を抽出する方がよいのではないですか。「age = 23」という1行のプロパティファイルと同様に、内部プログラム構造の知識を必要とするクラス名などの他の詳細を管理者に変更させません。
Pavel Feldman、2010年

私は最近、JavaコードとXSLTが混在するプロジェクトに取り組んでいました。チームはJavaに強い(そしておそらくXMLとXSLTでの作業にあまり慣れていない)人々の混合でした。そして、XMLとXSLTに非常に強い(そしてJavaにあまり慣れていない)人々。構成は2番目のグループによって管理される予定だったので、Springを使用し、XML構成を持つことは理にかなっています。言い換えれば、Springはチームの分業問題を解決しました。「技術的な」問題は解決しませんでした。構成は、Javaコードで簡単に実行できたという意味で。
Dawood ibnカリーム2011

「サポート担当者」は、依存関係注入コンテナ内で作成されているいくつかのクラスを変更する必要があることについて何か知っているでしょうか?本当にこれを行うのは開発者の仕事だと思い込んでいますか?
神保

それこそが、構成値(たとえば、統合するシステムのURL)を抽出することが理にかなっている理由です。サポート担当者がプロパティファイルまたは(最悪の場合)XMLファイルを編集しても、コンパイルされたJavaクラスは変わりません。
ミロA.

1

春の展望から私はあなたに二つの答えを与えることができます。

まず、XML構成が構成を定義する唯一の方法ではありません。ほとんどはアノテーションを使用して構成でき、XMLで実行する必要があるのは、ライブラリから使用している接続プールのように、ユーザーがとにかく記述していないコードの構成です。Spring 3には、例の手作業のDI構成と同様に、Javaを使用してDI構成を定義するメソッドが含まれています。したがって、Springを使用しても、XMLベースの構成ファイルを使用する必要があるわけではありません。

第二に、Springは単なるDIフレームワークではありません。トランザクション管理やAOPなど、他にも多くの機能があります。Spring XML構成では、これらすべての概念が組み合わされています。多くの場合、同じ構成ファイルでBeanの依存関係、トランザクション設定を指定し、バックグラウンドでAOPを使用して実際に処理したセッションスコープのBeanを追加しています。XML構成は、これらすべての機能を管理するためのより良い場所を提供することがわかりました。また、Javaベースの構成を行うよりも、アノテーションベースの構成とXML構成の方がスケールアップしやすいと感じています。

しかし、私はあなたの要点を理解しています。Javaでの依存性注入構成の定義には何の問題もありません。私は通常、単体テストで自分で行い、DIフレームワークを追加していないほど小さいプロジェクトで作業しているときは、私は通常、Javaで構成を指定しません。これは、Springを使用することを選択したときに、記述から離れようとしている種類の配管コードだからです。ただし、これは優先設定です。XML構成がJavaベースの構成よりも優れているという意味ではありません。


0

Springにはプロパティローダーもあります。このメソッドを使用して、環境に依存する変数を設定します(開発、テスト、受け入れ、本番など)。これは、たとえば、リッスンするキューにすることができます。

プロパティが変更される理由がない場合は、このように構成する理由もありません。


0

あなたのケースは非常にシンプルなので、SpringのようなIoC(Inversion of Control)コンテナは必要ありません。一方、「実装ではなくインターフェイスにプログラムする」場合(これはOOPの良い方法です)、次のようなコードを使用できます。

IService myService;
// ...
public void doSomething() {
  myService.fetchData();
}

(myServiceのタイプはIService-インターフェースであり、具体的な実装ではないことに注意してください)。これで、初期化時にIoCコンテナーにIServiceの正しい具象インスタンスを自動的に提供させると便利です。多くのインターフェイスと実装がある場合、手動で行うのは面倒です。IoCコンテナー(依存性注入フレームワーク)の主な利点は次のとおりです。

  • インターフェースとその具体的な実装間のマッピングの外部構成
  • IoCコンテナーは、複雑な依存関係グラフの解決、コンポーネントのライフタイムの管理など、いくつかのトリッキーな問題を処理します。
  • 手続き型コードではなく宣言的にマッピングを提供するため、コーディング時間を節約できます。
  • 制御の原則の反転により、実際の実装を偽の実装に置き換えることができるため(SQLデータベースをメモリ内の実装に置き換えるなど)、ユニットテストが容易になります。

0

XML構成ファイルで初期化すると、コンピューターにアプリを展開しているクライアントとのデバッグ/適応作業が簡略化されます。(再コンパイル+バイナリファイルの置換が不要なため)


-2

最も魅力的な理由の1つは、「ハリウッドの原則」です。私たちに電話しないでください。電話します。コンポーネントは、他のコンポーネントやサービス自体を検索する必要はありません。代わりに、自動的に提供されます。Javaでは、これはコンポーネント内でJNDIルックアップを行う必要がなくなったことを意味します。

また、コンポーネントを個別に単体テストする方がはるかに簡単です。必要なコンポーネントの実際の実装を提供する代わりに、(おそらく自動生成された)モックを使用するだけです。


この答えは、依存性注入についてです。私はそれが何であるかを知っており、それが良いことを知っており、質問の最初の文でそれを明確に述べています。問題は、単純な初期化コードと比較した場合のDI構成の利点についてでした。
Pavel Feldman、

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