依存性注入

翻訳者から



紹介している翻訳では、依存関係注入(DI)に関するJakob Jenkovの一連の記事が開きます。 このシリーズは、著者が「依存性」、「依存性注入」、「依存性注入用のコンテナー」などの概念の概念と実際の適用を分析し、オブジェクトの作成パターンを比較し、DIコンテナー(たとえばSpring)の特定の実装の欠点を分析する点で注目に値します、彼がどのようにして彼自身のDIコンテナを書くことになったかを伝えます。 したがって、読者は、アプリケーションの依存関係管理の問題についてかなり全体的な見解を得るように求められます。



この記事では、内部および外部(DI)からオブジェクトを構成するアプローチを比較します。 意味に関しては、この記事は「依存関係」とそのタイプの概念を定義するJakob Jenkov Understanding Dependenciesによる記事の続きです。









シリーズには、次の記事が含まれています





  1. 依存性注入
  2. 依存性注入コンテナ
  3. 依存性注入の利点
  4. 依存性注入を使用する場合
  5. 依存性注入はファクトリパターンを置き換えていますか?




依存性注入



Dependency Injectionは、Martin Fowlerの記事Inversion of Control Containers and the Dependency Injection Patternで最初に使用された式です。 これは良い記事ですが、依存性注入コンテナーの利点のいくつかを見落としています。 また、この記事の結論には同意しませんが、それについては以下のテキストで詳しく説明します。



依存性注入の説明



記事の本文に実例を示す著者のビデオ
依存性注入は、オブジェクトのフィールドが外部エンティティによって設定されるオブジェクトカスタマイズスタイルです。 つまり、オブジェクトは外部オブジェクトによってカスタマイズできます。 DIは、自己調整オブジェクトの代替です。 これはやや抽象的に見えるかもしれませんので、例を見てみましょう:



UPD:著者がflatscodefogoneで提示したコードの断片について議論した後、私はコードの論争の的となっている問題を修正することにしました。 元のアイデアは、コードに触れて作成者が作成したとおりにコードを提供することではありませんでした。 問題のある場所にある元の著作権コードは、「元の」という表示でコメントアウトされ、その修正されたバージョンは以下のとおりです。 また、元のコードは記事の冒頭のリンクにあります。



public class MyDao { // : protected DataSource dataSource = private DataSource dataSource = new DataSourceImpl("driver", "url", "user", "password"); //data access methods... public Person readPerson(int primaryKey) {...} }
      
      





このDAO(データアクセスオブジェクト)MyDaoには、データベース接続を取得するためにjavax.sql.DataSourceのインスタンスが必要です。 データベース接続は、Personオブジェクトなど、データベースの読み取りと書き込みに使用されます。



MyDaoクラスはデータソースが必要なため、DataSourceImplのインスタンスを作成することに注意してください。 MyDaoがDataSource実装を必要とするということは、それに依存することを意味します。 データソースを実装せずにその仕事をすることはできません。 したがって、MyDaoには、DataSourceインターフェイスとその実装の一部に「依存関係」があります。



MyDaoクラスは、DataSourceImplをDataSourceの実装としてインスタンス化します。 したがって、MyDaoクラス自体は「依存関係を解決します」。 クラスが自身の依存関係を解決するとき、クラスは依存関係を解決するクラスにも自動的に依存します。 この場合、MyDaoはDataSourceImplと、DataSourceImplコンストラクターに渡される4つのハードコードされた文字列値にも依存します。 これらの4行に他の値を使用したり、コードを変更せずにDataSourceインターフェイスの別の実装を使用したりすることはできません。



ご覧のとおり、クラスが独自の依存関係を解決すると、これらの依存関係に関して柔軟性がなくなります。 これは悪いです。 つまり、依存関係を変更する必要がある場合は、コードを変更する必要があります。 この例では、これは、別のデータベースを使用する必要がある場合、MyDaoクラスを変更する必要があることを意味します。 この方法で多数のDAOクラスを実装している場合は、すべてを変更する必要があります。 さらに、DataSource実装をロックしてMyDaoユニットテストを実施することはできません。 DataSourceImplのみを使用できます。 これが悪い考えであることを理解するのにそれほど知性は必要ありません。



デザインを少し変更してみましょう。



 public class MyDao { // : protected DataSource dataSource = null; private final DataSource dataSource; public MyDao(String driver, String url, String user, String password){ this.dataSource = new DataSourceImpl(driver, url, user, password); } //data access methods... public Person readPerson(int primaryKey) {...} }
      
      





DataSourceImplのインスタンス化はコンストラクターに移動されていることに注意してください。 コンストラクターは4つのパラメーターを取ります。これらは、DataSourceImplに必要な4つの値です。 MyDaoクラスは依然としてこれら4つの値に依存していますが、依存関係自体は解決していません。 MyDaoをインスタンス化するクラスによって提供されます。 依存関係はMyDaoコンストラクターに「注入」されます。 したがって、用語「依存関係の実装(Transl。::またはそうでなければ-インジェクション)」。 MyDaoクラスで使用されるデータベースドライバー、URL、ユーザー名、またはパスワードを変更せずに変更できるようになりました。



依存性注入は設計者に限定されません。 依存関係は、セッターメソッドを使用して、またはパブリックフィールドを介して直接実装することもできます( 約Transl。:フィールドについてトランスレーターが同意しないため、クラスデータの保護に違反します)。



MyDaoクラスは、より独立している場合があります。 現在でも、DataSourceインターフェイスとDataSourceImplクラスの両方に依存しています。 DataSourceインターフェイス以外に依存する必要はありません。 これは、4つの文字列型パラメーターの代わりに、DataSourceをコンストラクターに注入することで実現できます。 これは次のようなものです。



 public class MyDao { // : protected DataSource dataSource = null; private final DataSource dataSource; public MyDao(DataSource dataSource){ this.dataSource = dataSource; } //data access methods... public Person readPerson(int primaryKey) {...} }
      
      





これで、MyDaoクラスはDataSourceImplクラスまたはDataSourceImplコンストラクターに必要な4行に依存しなくなりました。 これで、MyDaoのコンストラクターでDataSourceの任意の実装を使用できます。



チェーン依存性注入



前のセクションの例は少し簡略化されています。 依存関係がMyDaoクラスからMyDaoクラスを使用するすべてのクライアントに移動されたと主張するかもしれません。 お客様は、MyDaoコンストラクターにDataSource実装を配置できるように、DataSource実装を認識する必要があります。 以下に例を示します。



 public class MyBizComponent{ public void changePersonStatus(Person person, String status){ MyDao dao = new MyDao( new DataSourceImpl("driver", "url", "user", "password")); Person person = dao.readPerson(person.getId()); person.setStatus(status); dao.update(person); } }
      
      





ご覧のとおり、MyBizComponentはDataSourceImplクラスとそのコンストラクターに必要な4行に依存しています。 これは、MyDaoがクラスや、使用すらしていない情報に依存するようになったため、MyDaoがそれらに依存しているよりもさらに悪化しています。 さらに、DataSourceImplおよびコンストラクターパラメーターの実装は、抽象化の異なるレイヤーに属します。 MyBizComponentの下のレイヤーはDAOレイヤーです。



解決策は、すべてのレイヤーに依存関係を実装し続けることです。 MyBizComponentはMyDaoインスタンスのみに依存する必要があります。 これは次のようなものです。



  public class MyBizComponent{ // : protected MyDao dao = null; private final MyDao dao; public MyBizComponent(MyDao dao){ this.dao = dao; } public void changePersonStatus(Person person, String status){ Person person = dao.readPerson(person.getId()); person.setStatus(status); dao.update(person); } }
      
      





再び、依存関係MyDaoがコンストラクターを通じて提供されます。 現在、MyBizComponentはMyDaoクラスのみに依存しています。 MyDaoがインターフェイスである場合、MyBizComponentの知識がなくても実装を変更できます。



依存性注入のこのパターンは、最下層(データアクセス層)からユーザーインターフェイス(存在する場合)まで、アプリケーションのすべての層を通して継続する必要があります。



はじめに



All Articles