依存性の注入とは? わかりやすく解説

Weblio 辞書 > コンピュータ > IT用語辞典 > 依存性の注入の意味・解説 

DI

プログラミングのほかの用語一覧
開発環境:  オペランド  CVS  Delphi  DI  Eclipse  GitHub  バリデーション

依存性の注入

出典: フリー百科事典『ウィキペディア(Wikipedia)』 (2023/05/27 04:32 UTC 版)

依存性の注入(いぞんせいのちゅうにゅう、: Dependency injection)とは、あるオブジェクトや関数が、依存する他のオブジェクトや関数を受け取るデザインパターンである。英語の頭文字からDIと略される。DIは制御の反転の一種で、オブジェクトの作成と利用について関心の分離を行い、疎結合なプログラムを実現することを目的としている。

dependencyを「依存性」と訳すのは本来の意味[1] から外れているため「依存オブジェクト注入」の用語を採用する文献も複数存在する[2][3]

概要

DIを利用したプログラムを作成する場合、コンポーネント間の関係はインタフェースを用いて記述し、具体的なコンポーネントを指定しない。具体的にどのコンポーネントを利用するかは別のコンポーネントや外部ファイル等を利用することで、コンポーネント間の依存関係を薄くすることができる。

依存関係がプログラムから外部に取り除かれることで、以下のようなメリットが発生する[4]

Dependency injectionという用語を作成したのはソフトウェア開発者のマーティン・ファウラーである。類似の概念としてそれ以前から制御の反転 (IoC) と呼ばれるアイデアが存在していたが、それを整理・範囲を限定することでDIが生み出された。現在では代表的なDIコンテナとして知られるSpring Frameworkも、誕生当初はDIではなくIoCという表現を用いていた。DIは2000年代前半のJavaによる開発において、極めて複雑な標準仕様となっていたJava EE(現・Jakarta EE)の特にEJBに対する批判を背景に広く用いられるようになった[4]。 その概念は後に標準仕様にも取り込まれ、2007年のJava EE 5では限定的な機能を備えたEJB 3.0が、2009年のJava EE 6ではより汎用的なDIコンテナとしての機能を備えたCDIが定義されている[5]

DIの種類

プログラムに依存性を注入する方法としては、以下のような手法が存在する。

インタフェース注入
注入用のインタフェースを定義して注入を行う方法
setter 注入
setter メソッドを定義して注入を行う方法
コンストラクタ注入
コンストラクタを定義して注入を行う方法

DIの例として、以下にJavaによるDIを用いない場合と手動でのDI、ならびにDIコンテナをイメージした自動でのDIのサンプルコードを示す。

初めに、一連のサンプルで用いる各コンポーネントのインタフェースを、株式売買を例題にして示す。

public interface IOnlineBrokerageService {
    String[] getStockSymbols();
    double getBidPrice(String stockSymbol);
    double getAskPrice(String stockSymbol);
    void putBuyOrder(String stockSymbol, int shares, double buyPrice);
    void putSellOrder(String stockSymbol, int shares, double sellPrice);
}

public interface IStockAnalysisService {
    double getEstimatedValue(String stockSymbol);
}

public interface IAutomatedStockTrader {
    void executeTrades();
}

DIを用いない状態

以下はDIを用いない場合の実装例である。

public class VerySimpleStockTraderImpl implements IAutomatedStockTrader {

    private IStockAnalysisService analysisService = new StockAnalysisServiceImpl();
    private IOnlineBrokerageService brokerageService = new NewYorkStockExchangeBrokerageServiceImpl();

    public void executeTrades() {
        . // omitted
    }
}

public class MyApplication {
    public static void main(String[] args) {
        IAutomatedStockTrader stockTrader = new VerySimpleStockTraderImpl();
        stockTrader.executeTrades();
    }
}

VerySimpleStockTraderImplクラスでは、直接IStockAnalysisService, IOnlineBrokerageServiceインタフェースを実装したクラスのインスタンスを作成しており、これらの実装に深く依存してしまっている。

手動でのDI

上記のコードを、手動でDIを行うようにリファクタリングすると下記のようになる。

public class VerySimpleStockTraderImpl implements IAutomatedStockTrader {

    private IStockAnalysisService analysisService;
    private IOnlineBrokerageService brokerageService;

    public VerySimpleStockTraderImpl(
            IStockAnalysisService analysisService,
            IOnlineBrokerageService brokerageService) {
        this.analysisService = analysisService;
        this.brokerageService = brokerageService;
    }
    public void executeTrades() {
        
    }
}

public class MyApplication {
    public static void main(String[] args) {
        IStockAnalysisService analysisService = new StockAnalysisServiceImpl();
        IOnlineBrokerageService brokerageService = new NewYorkStockExchangeBrokerageServiceImpl();

        IAutomatedStockTrader stockTrader = new VerySimpleStockTraderImpl(
            analysisService,
            brokerageService);
        stockTrader.executeTrades();
    }
}

この例では、MyApplication.main()が依存性の注入を行っており、VerySimpleStockTraderImpl自体は特定の実装に依存しなくなっている。なお、この実装ではコンストラクタ注入の手法が用いられている。

自動的なDI

DIコンテナを用いることで、依存性の注入をコード上に直接記述せず、自動的に行うことが可能である。こうした手法を用いる場合、依存性は外部のXMLファイルやメタデータにて定義する。上記のコードを、XMLを用いるDIコンテナを使用するようリファクタリングした例が下記である。

    <contract id="IAutomatedStockTrader">
        <implementation>VerySimpleStockTraderImpl</implementation>
    </contract>
    <contract id="IStockAnalysisService" singleton="true">
        <implementation>StockAnalysisServiceImpl</implementation>
    </contract>
    <contract id="IOnlineBrokerageService" singleton="true">
        <implementation>NewYorkStockExchangeBrokerageServiceImpl</implementation>
    </contract>
public class VerySimpleStockTraderImpl implements IAutomatedStockTrader {
    private IStockAnalysisService analysisService;
    private IOnlineBrokerageService brokerageService;

    public VerySimpleStockTraderImpl(
            IStockAnalysisService analysisService,
            IOnlineBrokerageService brokerageService) {
        this.analysisService = analysisService;
        this.brokerageService = brokerageService;
    }
    public void executeTrades() {
         // omitted
    }
}

public class MyApplication {
    public static void main(String[] args) {
        IAutomatedStockTrader stockTrader =
            (IAutomatedStockTrader) DependencyManager.create(IAutomatedStockTrader.class);
        stockTrader.executeTrades();
    }
}

この例では、IAutomatedStockTraderのどの実装を使用するかの判断はDIコンテナに委ねられている。インタフェースが要求されたDIコンテナは、設定ファイルに基づきその実装であるVerySimpleStockTraderImplクラスのインスタンスを返す。さらに、VerySimpleStockTraderImplIStockAnalysisServiceIOnlineBrokerageServiceの依存性に対して、同様にコンストラクタ注入を行う。

DIコンテナには数多くの種類があり、上で示した例はそのごく一部でしかない。実際にはDIコンテナごとに様々な手法が用いられている。

DIを用いた単体テスト

DIを用いることで、単体テストにおいて簡単に依存性をテスト用のクラス(モックオブジェクト等)に差し替えることができる。以下はDIを用いた、前述のVerySimpleStockTraderImplクラスのテストケースの例である。この例では、IOnlineBrokerageService, IStockAnalysisServiceインタフェースを実装したテスト用クラスを作成し、DIによりそれを注入することで、実際のクラスを用いることなく、単体テストを実現している。

public class VerySimpleStockBrokerTest {
    // IOnlineBrokerageServiceを実装した単純なスタブ
    public class StubBrokerageService implements IOnlineBrokerageService {
        public String[] getStockSymbols() { 
            return new String[] {"ACME"};
        }
        public double getBidPrice(String stockSymbol) {
            return 100.0; // (テストに十分な値)
        }
        public double getAskPrice(String stockSymbol) { 
            return 100.25;
        }
        public void putBuyOrder(String stockSymbol, int shares, double buyPrice) {
             Assert.Fail("Should not buy ACME stock!");
        }
        public void putSellOrder(String stockSymbol, int shares, double sellPrice) {
             // このテストでは使用しない
             throw new NotImplementedException(); 
        }
    }

    public class StubAnalysisService implements IStockAnalysisService {
        public double getEstimatedValue(String stockSymbol) {
            if (stockSymbol.equals("ACME")) 
                return 1.0;
            return 100.0;
        }
    }

    public void TestVerySimpleStockTraderImpl() {
        // このテスト専用の依存性を指定するため、DIコンテナに直接登録している
        DependencyManager.register(
            IOnlineBrokerageService.class,
            StubBrokerageService.class);
        DependencyManager.register(
            IStockAnalysisService.class,
            StubAnalysisService.class);

        IAutomatedStockTrader stockTrader =
            (IAutomatedStockTrader) DependencyManager.create(IAutomatedStockTrader.class);
        stockTrader.executeTrades();
    }
}

実装がDBネットワークにアクセスする場合、また古いEJBのような重たいコンポーネントの場合、そのままでは単体テストを行うことは難しい。しかし、上記のようにDIを用いて依存関係のみをテスト用のものに差し替えることで、本来のテスト対象のプログラムには手を加えることなく、簡単に単体テストを行うことができる。[4]

HTML

マークアップ言語であるHTML (HyperText Markup Language) でも依存性の注入がおこなわれる。

WebComponents(カスタム要素 + Template要素+ ShadowDOM)の登場により、巨大なHTMLファイルを小さなHTML要素コンポーネントの集合として記述することが可能になった。しかし大きなコンポーネント Big が小さなコンポーネント Small を包む形でコーディングすると、Big が Small に依存してしまう。そこでslot要素を用いた依存性の注入がおこなわれる。slot要素は弱いinterfaceとして働き、slot要素を用いて定義されたカスタム要素を利用する際に依存性をタグで囲むことで注入できる。

下記の例では大きなコンポーネント<my-element-with-slot>が2つの受け入れ可能slotを持っている。利用時にslotを指定したspan要素を挿入することで、<my-element-with-slot>はspan要素に直接依存せずにspan要素を利用できる。プログラミング言語のような明示的interfaceがない(interfaceによる型指定slot要素がない)ために型支援を受けた安全な依存性の注入は現時点ではおこなえないが、適切に設計することで依存性を切り分けることは可能である。

    <!--when define-->
    <script>
      class myElementWithSlot extends HTMLElement {
        constructor() {
          super();
          const shadowRoot = this.attachShadow({ mode: "open" });
          shadowRoot.innerHTML = `
            <h2>My Element</h2>
            <h3>inserted #1: <slot name="slot1">no contents</slot></h3>
            <h4>inserted #2: <slot name="slot2">no contents</slot></h4>
          `;
        }
      }
      customElements.define("my-element-with-slot", myElementWithSlot);
    </script>

    <!--when use-->
    <my-element-with-slot>
      <span slot="slot1">dependency-one</span>
      <span slot="slot2">dependency-two</span>
    </my-element-with-slot>

DIコンテナ

DIの機能を提供するフレームワークはDIコンテナと呼ばれる[4]。 主なDIコンテナとしては、下記のようなものが存在する。

Java

.NET

PHP

注釈・出典

  1. ^ Dependency Definition & Meaning - Merriam-Webster”. Merriam-Webster. 2022年9月3日閲覧。 “: something that is dependent on something else especially : a territorial unit under the jurisdiction of a nation but not formally annexed by it”
  2. ^ 『Seasar2で学ぶ DIとAOP アスペクト指向によるJava開発』技術評論社、2006年8月9日。 
  3. ^ 『オブジェクト指向設計実践ガイド ~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方』技術評論社、2016年9月2日。 
  4. ^ a b c d Java開発を変える最新の設計思想「Dependency Injection(DI)」とは”. ITPro (2005年2月18日). 2014年2月20日閲覧。
  5. ^ Java EE 6: Understanding Contexts and Dependency Injection (CDI), Part 1”. オラクル (2010年5月25日). 2014年2月20日閲覧。
  6. ^ Microsoft.Extensions.DependencyInjection Namespace | Microsoft Docs

関連項目


依存性の注入

出典: フリー百科事典『ウィキペディア(Wikipedia)』 (2021/08/11 01:34 UTC 版)

オブジェクト指向分析設計」の記事における「依存性の注入」の解説

依存性の注入 (dependency injection) の基本的な考えは、あるオブジェクトが何か別のオブジェクトへの参照をもつことに依存しているのであれば依存される側のオブジェクト依存する側のオブジェクトに「注入」する、ということである。例えば、データベース接続表現するオブジェクト必要なオブジェクトがあるのであれば、そのオブジェクト内でデータベース接続オブジェクト生成するではなく、そのオブジェクトコンストラクタ (新たなオブジェクト生成する際に呼び出される手続き) への引数 (パラメタ) として、データベース接続オブジェクトをそのオブジェクトに渡すのである

※この「依存性の注入」の解説は、「オブジェクト指向分析設計」の解説の一部です。
「依存性の注入」を含む「オブジェクト指向分析設計」の記事については、「オブジェクト指向分析設計」の概要を参照ください。

ウィキペディア小見出し辞書の「依存性の注入」の項目はプログラムで機械的に意味や本文を生成しているため、不適切な項目が含まれていることもあります。ご了承くださいませ。 お問い合わせ


英和和英テキスト翻訳>> Weblio翻訳
英語⇒日本語日本語⇒英語
  

辞書ショートカット

すべての辞書の索引

「依存性の注入」の関連用語

依存性の注入のお隣キーワード
検索ランキング

   

英語⇒日本語
日本語⇒英語
   



依存性の注入のページの著作権
Weblio 辞書 情報提供元は 参加元一覧 にて確認できます。

   
IT用語辞典バイナリIT用語辞典バイナリ
Copyright © 2005-2025 Weblio 辞書 IT用語辞典バイナリさくいん。 この記事は、IT用語辞典バイナリの【DI】の記事を利用しております。
ウィキペディアウィキペディア
All text is available under the terms of the GNU Free Documentation License.
この記事は、ウィキペディアの依存性の注入 (改訂履歴)の記事を複製、再配布したものにあたり、GNU Free Documentation Licenseというライセンスの下で提供されています。 Weblio辞書に掲載されているウィキペディアの記事も、全てGNU Free Documentation Licenseの元に提供されております。
ウィキペディアウィキペディア
Text is available under GNU Free Documentation License (GFDL).
Weblio辞書に掲載されている「ウィキペディア小見出し辞書」の記事は、Wikipediaのオブジェクト指向分析設計 (改訂履歴)の記事を複製、再配布したものにあたり、GNU Free Documentation Licenseというライセンスの下で提供されています。

©2025 GRAS Group, Inc.RSS