

ソフトウェア エンジニアリングにおいて、依存性注入とは、オブジェクトまたは関数が、内部で作成するのではなく、必要な他のオブジェクトまたは関数を受け取るプログラミング手法です。依存性注入は、オブジェクトの構築と使用の懸念を分離し、疎結合プログラムを実現することを目的としています。[1] [2] [3]このパターンにより、特定のサービスを使用するオブジェクトまたは関数は、それらのサービスの構築方法を知る必要がなくなります。代わりに、受信側の「クライアント」(オブジェクトまたは関数)には、外部コード(「インジェクター」)によって依存関係が提供されますが、クライアントはそれを認識していません。[4]依存性注入により、暗黙的な依存関係が明示的になり、次の問題の解決に役立ちます。[5]
- クラスは、それが依存するオブジェクトの作成から独立するにはどうすればよいでしょうか?
- アプリケーションとそれが使用するオブジェクトはどのようにしてさまざまな構成をサポートできるのでしょうか?
依存性注入は、依存性逆転の原則に沿ってコードを維持するためによく使用されます。[6] [7]
静的に型付けされた言語で依存性注入を使用すると、クライアントは具体的な実装ではなく、使用するサービスのインターフェースのみを宣言すればよく、再コンパイルせずに実行時に使用されるサービスを変更することが容易になります。
アプリケーションフレームワークは依存性注入と制御の反転を組み合わせることが多い。制御の反転では、フレームワークは最初にオブジェクト(コントローラーなど)を構築し、次に制御フローをそのオブジェクトに渡します。依存性注入では、フレームワークはアプリケーションオブジェクトによって宣言された依存性(多くの場合、コンストラクターメソッドのパラメーター内)をインスタンス化し、その依存性をオブジェクトに渡します。[8]
依存性注入は「依存性の実装に対する制御の反転」という考え方を実装しており、そのため一部のJavaフレームワークではこの概念を総称して「制御の反転」と呼んでいます(制御フローの反転と混同しないでください)。[9]
役割
5歳児への依存性注入
冷蔵庫から自分で物を取り出すと、問題を引き起こす可能性があります。ドアを開けたままにしたり、ママやパパが欲しくないものを持ってきたりするかもしれません。私たちが持っていないものや賞味期限切れのものを探している可能性もあります。
あなたがすべきことは、「昼食と一緒に何か飲み物が必要です」という要望を述べることです。そうすれば、座って何かを食べるときに、私たちが何か用意します。
依存性注入には、サービス、クライアント、インターフェース、インジェクターの 4 つの役割が関係します。
サービスとクライアント
サービスとは、便利な機能を備えたクラスのことです。一方、クライアントとは、サービスを利用するクラスのことです。クライアントが必要とするサービスは、クライアントの依存関係です。
どのオブジェクトもサービスまたはクライアントになることができます。名前は、オブジェクトが注入時に果たす役割にのみ関連しています。同じオブジェクトがクライアント(注入されたサービスを使用する)とサービス(他のオブジェクトに注入される)の両方になることもあります。注入されると、サービスはクライアントの状態の一部になり、使用できるようになります。[12]
インターフェース
クライアントは依存関係がどのように実装されているかを知る必要はなく、その名前とAPIだけを知る必要があります。たとえば、電子メールを取得するサービスは、裏でIMAPまたはPOP3プロトコルを使用することがありますが、この詳細は、電子メールを取得するだけのコード呼び出しには関係ない可能性があります。実装の詳細を無視することで、クライアントは依存関係が変更されても変更する必要がなくなります。
インジェクター
インジェクターは、アセンブラー、コンテナー、プロバイダー、またはファクトリーとも呼ばれ、クライアントにサービスを導入します。
インジェクターの役割は、複雑なオブジェクト グラフを構築して接続することです。オブジェクトはクライアントとサービスの両方になる場合があります。 インジェクター自体は、連携して動作する多数のオブジェクトである可能性がありますが、循環依存関係を作成するため、クライアントであってはなりません。
依存性注入はオブジェクトの構築方法と使用方法を分離するため、newほとんどのオブジェクト指向言語にあるキーワードの重要性が薄れることが多い。フレームワークがサービスの作成を処理するため、プログラマーはプログラムのドメイン内のエンティティを表す値オブジェクトEmployee(ビジネスアプリ内のオブジェクトやショッピングアプリ内のオブジェクトなどOrder)のみを直接構築する傾向がある。[13] [14] [15] [16]
類推
類推すると、自動車は人をある場所から別の場所へ輸送するという有用な仕事をするサービスと考えることができます。自動車のエンジンにはガソリン、ディーゼル、電気が必要ですが、この詳細はクライアントであるドライバーにとっては重要ではなく、目的地まで行けるかどうかだけが重要です。
自動車は、ペダル、ハンドル、その他のコントロールを通じて統一されたインターフェースを提供します。そのため、工場のラインでどのエンジンが「注入」されたかは問題ではなくなり、ドライバーは必要に応じてあらゆる種類の車を切り替えることができます。
利点と欠点
利点
依存性注入の基本的な利点は、クラスとその依存関係間の結合度が低下することです。[17] [18]
依存関係がどのように実装されているかについてのクライアントの知識を取り除くことで、プログラムの再利用性、テスト性、保守性が向上します。[19]
これにより柔軟性も向上します。クライアントは、クライアントが期待する固有のインターフェースをサポートするものであれば何でも実行できます。[20]
より一般的には、依存性注入では、すべての依存性の作成が単一のコンポーネントによって処理されるため、定型コードが削減されます。[19]
最後に、依存性注入により同時開発が可能になります。2人の開発者が互いに使用するクラスを独立して開発でき、必要なのはクラスが通信するインターフェースだけです。プラグインは、元の製品の開発者と話をすることさえないサードパーティによって開発されることがよくあります。[21]
テスト
依存性注入の利点の多くは、特にユニットテストに関連しています。
たとえば、依存性注入を使用すると、システムの構成の詳細を構成ファイルに外部化することができ、再コンパイルせずにシステムを再構成できるようになります。コンポーネントの異なる実装を必要とするさまざまな状況に合わせて、個別の構成を記述することができます。[22]
同様に、依存性注入ではコードの動作を変更する必要がないため、リファクタリングとしてレガシー コードに適用できます。これにより、クライアントの独立性が高まり、テスト対象ではない他のオブジェクトをシミュレートするスタブまたはモック オブジェクトを使用して、クライアントを分離して単体テストすることが容易になります。
このテストの容易さは依存性注入を使用する際に最初に気づく利点であることが多い。[23]
デメリット
依存性注入の批評家は次のように主張します。
- 詳細な設定を要求するクライアントを作成しますが、明らかなデフォルトが利用可能な場合には面倒になる可能性があります。[21]
- 動作と構築を分離するため、コードの追跡が困難になります。[21]
- 通常はリフレクションや動的プログラミングで実装されるため、IDEの自動化が妨げられます。[24]
- 通常、より多くの先行開発努力が必要になります。[25]
- フレームワークへの依存を促進する。[26] [27] [28]
依存性注入の種類
クライアントが注入されたサービスを受けるには、主に3つの方法があります。[29]
- コンストラクター インジェクション。依存関係はクライアントのクラスコンストラクターを通じて提供されます。
- セッター インジェクション。クライアントが依存関係を受け入れるセッター メソッドを公開します。
- インターフェース インジェクション。依存関係のインターフェースが、渡されたクライアントに依存関係を注入するインジェクター メソッドを提供します。
いくつかのフレームワークでは、クライアントは依存性注入を積極的に受け入れる必要がありません。例えばJavaでは、リフレクションによってテスト時にプライベート属性をパブリックにし、サービスを直接注入することができます。 [30]
依存性注入なし
次のJava の例では、クラスにはコンストラクターで初期化されたメンバー変数がClient含まれています。クライアントは、使用するサービスを直接構築および制御し、ハードコードされた依存関係を作成します。
Service
パブリッククラスClient {プライベートServiceサービス;
Client () { // 依存関係はハードコードされています。this . service = new ExampleService (); } }
コンストラクタインジェクション
依存性注入の最も一般的な形式は、クラスがコンストラクターを通じて依存性を要求することです。これにより、必要な依存性がなければクライアントをインスタンス化できないため、クライアントが常に有効な状態になることが保証されます。
パブリッククラスClient {プライベートServiceサービス;
// 依存関係はコンストラクターを通じて注入されます。
Client ( Service service ) { if ( service == null ) { throw new IllegalArgumentException ( "service は null であってはなりません" ); } this . service = service ; } }
セッター注入
コンストラクターではなく、セッター メソッドを通じて依存関係を受け入れることにより、クライアントはインジェクターがいつでも依存関係を操作できるようにすることができます。これにより柔軟性が高まりますが、クライアントが使用される前にすべての依存関係が注入され、有効であることを確認することが難しくなります。
パブリッククラスClient {プライベートServiceサービス;
// 依存関係はセッターメソッドを通じて注入されます。public
void setService ( Service service ) { if ( service == null ) { throw new IllegalArgumentException ( "service は null にしてはいけません" ) ; } this . service = service ; } }
インターフェース注入
インターフェース インジェクションを使用すると、依存関係はクライアントを完全に無視しますが、新しいクライアントへの参照を送受信します。
このようにして、依存関係はインジェクターになります。重要なのは、注入メソッドがインターフェースを通じて提供されることです。
クライアントとその依存関係を導入するには、アセンブラが必要です。アセンブラはクライアントへの参照を取得し、それをその依存関係を設定するセッター インターフェイスにキャストし、それをその依存関係オブジェクトに渡します。依存関係オブジェクトは、次にそれ自体への参照をクライアントに返します。
インターフェイス インジェクションに価値を持たせるには、依存関係は単に自分自身への参照を返すだけでなく、何かを行う必要があります。これは、他の依存関係を解決するためのファクトリまたはサブアセンブラとして動作し、メイン アセンブラからいくつかの詳細を抽象化することができます。依存関係がそれを使用しているクライアントの数を把握できるように、参照カウントを行うこともできます。依存関係がクライアントのコレクションを維持している場合、後でそれらすべてにそれ自体の異なるインスタンスを注入することができます。
パブリックインターフェイスServiceSetter { void setService ( Serviceサービス); }
パブリッククラスClient はServiceSetterを実装します{プライベートService service ;
@Override
public void setService ( Service service ) { if ( service == null ) { throw new IllegalArgumentException ( "service は null にできません" ); } this . service = service ; } }
パブリッククラスServiceInjector {プライベートfinal Set < ServiceSetter >クライアント= new HashSet <> ();
public void inject ( ServiceSetter client ) { this.clients.add ( client ) ; client.setService ( new ExampleService ( ) ) ; }
public void switch ( ) { for ( Client client : this.clients ) { client.setService ( new AnotherExampleService ( ) ) ; } } }
パブリッククラスExampleService はService {}を実装します。
パブリッククラスAnotherExampleServiceはService {}を実装します。
組み立て
依存性注入を実装する最も簡単な方法は、サービスとクライアントを手動で配置することです。これは通常、実行が開始されるプログラムのルートで行われます。
パブリッククラスプログラム{
public static void main ( String [] args ) { // サービスを構築します。Service service = new ExampleService ();
// サービスをクライアントに注入します。Client
client = new Client ( service ) ;
//オブジェクトを使用します。System.out.println ( client.greet ( ) ) ; } }
手作業による建設はより複雑になり、建設業者、工場、またはその他の建設パターンが必要になる場合があります。
フレームワーク

大規模なプロジェクトでは、手動の依存性注入は面倒でエラーが発生しやすいため、プロセスを自動化するフレームワークの使用が推奨されています。構築コードがアプリケーション固有のものではなく、汎用的なものになると、手動の依存性注入は依存性注入フレームワークになります。 [31]これらのツールは便利ですが、依存性注入を実行するために必須ではありません。[32] [33]
Springなどの一部のフレームワークでは、外部構成ファイルを使用してプログラムの構成を計画できます。
org.springframework.beans.factory.BeanFactoryをインポートします。org.springframework.context.ApplicationContextをインポートします。org.springframework.context.support.ClassPathXmlApplicationContextをインポートします。
パブリッククラスインジェクタ{
public static void main ( String [] args ) { // 使用する具体的なサービスに関する詳細は、プログラム自体とは別の構成に保存されます。BeanFactory beanfactory = new ClassPathXmlApplicationContext ( "Beans.xml" ); Client client = ( Client ) beanfactory . getBean ( "client" ); System . out . println ( client . greeting ()); } }
オブジェクトグラフが長くて複雑になる可能性がある場合でも、コード内で言及される唯一のクラスはエントリポイントであり、この場合はですClient。SpringClientで動作するように変更されておらず、POJOのままです。[34] [35] [36] Spring固有のアノテーションと呼び出しが多くのクラスに広がらないようにすることで、システムはSpringに緩く依存するだけです。[27]
例
アンギュラー
次の例は、依存性注入を通じてグリーティング サービスを受信する AngularJSコンポーネントを示しています。
関数SomeClass ( greeter ) { this.greeter = greetinger ; }
SomeClass.prototype.doSomething = function ( name ) { this.greeter.greet ( name ) ; }
各 AngularJS アプリケーションには、依存関係の構築と検索を担当するサービス ロケータが含まれています。
// モジュール内の配線情報を提供します
var myModule = angular . module ( 'myModule' , []);
// インジェクターに Greeter サービスの構築方法を教えます。//
Greeter は $window サービスに依存します。myModule
. factory ( ' greeter' , function ( $window ) { return { greeting : function ( text ) { $window . alert ( text ); } }; });
myModule次に、 Greeter サービスを含む、モジュール
で定義されたコンポーネントを提供する新しいインジェクターを作成できます。
var injector = angular.injector ([ 'myModule' , ' ng ' ]); var greetinger = injector.get ( ' greeter' ) ;
サービス ロケータのアンチパターンを回避するために、AngularJS では、コンポーネントの作成をインジェクタに委任する宣言型表記を HTML テンプレートで使用できます。
< div ng-controller = "MyController" >
< button ng-click = "sayHello()" >こんにちは</ button >
</ div >
function MyController ( $scope 、greetinger ) { $scope . sayHello = function () { greetinger . greeting ( 'Hello World' ); }; }
ディレクティブng-controllerはインジェクターをトリガーして、コントローラーとその依存関係のインスタンスを作成します。
C#
このサンプルは、 C#でのコンストラクター インジェクションの例を示します。
システムの使用;
名前空間DependencyInjection ;
// クライアントはこのインターフェースのみを認識し、どのゲームパッドを使用しているかは認識しません。
interface IGamepadFunctionality { string GetGamepadName (); void SetVibrationPower ( float power ); }
// 以下のサービスは、上記のインターフェースの具体的な実装を提供します。
クラスXboxGamepad : IGamepadFunctionality { float movementPower = 1.0f ; public string GetGamepadName () => "Xbox コントローラー" ; public void SetVibrationPower ( float power ) => this . movementPower = Math . Clamp ( power , 0.0f , 1.0f ); }
class PlaystationJoystick : IGamepadFunctionality { float vibratingPower = 100.0f ; public string GetGamepadName () => "PlayStation コントローラー" ; public void SetVibrationPower ( float power ) => this . vibratingPower = Math . Clamp ( power * 100.0f , 0.0f , 100.0f ); }
class SteamController : IGamepadFunctionality { double vibrating = 1.0 ; public string GetGamepadName () => "Steam コントローラー" ; public void SetVibrationPower ( float power ) => this . vibrating = Convert . ToDouble ( Math . Clamp ( power , 0.0f , 1.0f )); }
// このクラスはサービスを受信するクライアントです。
class Gamepad { IGamepadFunctionality gamepadFunctionality ;
// サービスはコンストラクターを通じて注入され、上記のフィールドに格納されます。public
Gamepad ( IGamepadFunctionality gamepadFunctionality ) = > this . gamepadFunctionality = gamepadFunctionality ;
public void Showcase () { // 挿入されたサービスが使用されます。var gamepadName = this . gamepadFunctionality . GetGamepadName (); var message = $"現在 {gamepadName} を使用しています。振動の強さを変更しますか?" ; Console . WriteLine ( message ); } }
class Program { static void Main () { var steamController = new SteamController (); // XboxController、PlaystationJoystick なども渡すことができます。// ゲームパッドは使用しているものを認識しておらず、認識する必要もありません。var gamepad = new Gamepad ( steamController ); gamepad . Showcase (); } }
行く
Goはクラスをサポートしておらず、依存性注入は通常、リフレクションまたはジェネリック(後者はGo 1.18 [37]以降でサポートされています)を利用する専用ライブラリによって抽象化されます。[38]依存性注入ライブラリを使用しないより単純な例を、次のMVC Webアプリケーションの例で示します。
まず、必要な依存関係をルーターに渡し、次にルーターからコントローラーに渡します。
パッケージルーター
インポート( "database/sql" "net/http"
「例/コントローラ/ユーザー」
「github.com/go-chi/chi/v5」「github.com/go-chi/chi/v5/middleware
」
"github.com/redis/go-redis/v9"
"github.com/rs/zerolog" )
type RoutingHandler struct { // ポインターによって値を呼び出しスタックのさらに下へ渡す// 新しいコピーを作成しないので、メモリを節約できるlog * zerolog . Logger db * sql . DB cache * redis . Client router chi . Router }
// 接続、ロガー、キャッシュは通常メイン関数で初期化されます
func NewRouter ( log * zerolog . Logger , db * sql . DB , cache * redis . Client , ) ( r * RoutingHandler ) { rtr := chi . NewRouter ()
return & RoutingHandler { log : log , db : db , cache : cache , router : rtr , } }
func ( r * RoutingHandler ) SetupUsersRoutes ( ) { uc : = users.NewController ( r.log , r.db , r.cache )
r . router . Get ( "/users/:name" 、func ( w http . ResponseWriter 、r * http . Request ) { uc . Get ( w 、r ) }) }
その後、カプセル化に違反することなく、ポインターレシーバーである任意のメソッドで構造体のプライベート フィールドにアクセスできます。
パッケージユーザー
インポート( "database/sql" "net/http"
「例/モデル」
"github.com/go-chi/chi/v5"
"github.com/redis/go-redis/v9" "github.com/rs/zerolog" )
タイプコントローラー構造体{ log * zerolog . Loggerストレージモデル. UserStorageキャッシュ* redis . Client }
func NewController ( log * zerolog.Logger , db * sql.DB , cache * redis.Client ) * Controller { return & Controller { log : log , storage : models.NewUserStorage ( db ) , cache : cache , } }
func ( uc * Controller ) Get ( w http.ResponseWriter , r * http.Request ) { //ミドルウェアでログをラップすることもできます。これはデモンストレーション目的です。uc.log.Info ( ) . Msg ( "ユーザーを取得しています" )
userParam := chi 。URLParam ( r , "名前" )
var user * models.User //キャッシュからユーザーを取得しますerr : = uc.cache.Get ( r.Context ( ) , userParam ).Scan ( & user ) if err ! = nil { uc.log.Error ( ). Err ( err ) .Msg ( "キャッシュからユーザーを取得中にエラーが発生しました。SQL ストレージから取得しています" ) }
user , err = uc.storage.Get ( r.Context ( ) , "johndoe" ) if err ! = nil { uc.log.Error (). Err ( err ) .Msg ( " SQL ストレージからユーザーを取得中にエラーが発生しました" ) http.Error ( w , "内部サーバーエラー" , http.StatusInternalServerError ) return } }
最後に、データ アクセス レイヤーのメイン関数で初期化されたデータベース接続を使用できます。
パッケージモデル
インポート( "database/sql" "time" )
タイプ( UserStorage構造体{ conn * sql . DB }
ユーザー構造体{名前文字列' json : "name" db : "name,primarykey" ' JoinedAt時刻.時刻' json : "joined_at" db : "joined_at" 'メール 文字列' json : "email" db : "email" ' } )
func NewUserStorage ( conn * sql . DB ) * UserStorage { return & UserStorage { conn : conn , } }
func ( us * UserStorage ) Get ( name string ) ( user * User , err error ) { // 'name' は一意のキーであると仮定query := "SELECT * FROM users WHERE name = $1"
err := us . conn . QueryRow ( query , name ). Scan ( & user ) ; err != nil { return nil , err }
ユーザーを返す、nil }
参照
参考文献
- ^ Seemann, Mark. 「依存性注入は疎結合である」。blog.ploeh.dk 。 2015年7月28日閲覧。
- ^ ab Seeman, Mark (2011 年 10 月)。. NET での依存性注入。Manning Publications。p. 4。ISBN 9781935182504。
- ^ Niko Schwarz、Mircea Lungu、Oscar Nierstrasz、「Seuss: きめ細かな構成可能性のために静的メソッドから責任を切り離す」、Journal of Object Technology、第 11 巻、第 1 号 (2012 年 4 月)、3:1–23 ページ。
- ^ “HollywoodPrinciple”. c2.com . 2015年7月19日閲覧。
- ^ 「依存性注入設計パターン - 問題、解決策、適用性」w3sDesign.com 。 2017年8月12日閲覧。
- ^ Erez, Guy (2022-03-09). 「依存性反転と依存性注入」. Medium . 2022-12-06閲覧。
- ^ Mathews, Sasha (2021-03-25). 「あなたは単に依存関係を注入しているだけで、依存関係の逆転に従っていると思っているだけです...」Medium 。 2022年12月6日閲覧。
- ^ 「Spring IoC コンテナー」。2023 年 5 月 23 日閲覧。
- ^ Fowler, Martin. 「Inversion of Control Containers and the Dependency Injection pattern」. MartinFowler.com . 2023 年6 月 4 日閲覧。
- ^ 「NET における依存性注入」(PDF) . philkildea.co.uk . p. 4. 2015 年 7 月 21 日時点のオリジナル(PDF)からアーカイブ。2015年 7 月 18 日に取得。
- ^ 「5歳児に依存性注入を説明するには?」。stackoverflow.com 。 2015年7月18日閲覧。
- ^ IT、Titanium。「James Shore: Dependency Injection Demystified」。www.jamesshore.com 。 2015年7月18日閲覧。
- ^ 「「新しい」か「新しい」でないか...」 2020年5月13日時点のオリジナルよりアーカイブ。2015年7月18日閲覧。
- ^ 「テスト可能なコードの書き方」www.loosecouplings.com . 2015年7月18日閲覧。
- ^ 「クリーンでテスト可能なコードを書く」www.ethanresnick.com . 2015年7月18日閲覧。
- ^ Sironi, Giorgio. 「いつ注射するか: 新しくできるものと注射できるものの区別 - 目に見えないもの」www.giorgiosironi.com 。 2015年7月18日閲覧。
- ^ 「the urban canuk, eh: 依存性注入とカプセル化違反の懸念について」www.bryancook.net 。2015年 7 月 18 日閲覧。
- ^ 「依存性注入設計パターン」。msdn.microsoft.com。2015年 7 月 18 日閲覧。
- ^ ab 「Java Community Process(SM) プログラム - JSR: Java 仕様要求 - 詳細 JSR# 330」。jcp.org。2015年 7 月 18 日閲覧。
- ^ 「3.1. 依存性注入 — Python 3: 何もないところから機械学習まで」。2020年2月8日時点のオリジナルよりアーカイブ。
- ^ abc 「Spring Java アプリケーション開発における依存性注入 (DI) の仕組み - DZone Java」。
- ^ 「Python での依存性注入と制御の反転 — Dependency Injector 4.36.2 ドキュメント」。
- ^ 「依存性注入のためのリファクタリング方法、パート 3: 大規模アプリケーション」。
- ^ 「依存性注入の簡単な紹介: 依存性注入とは何か、いつ使用するのか」2018 年 10 月 18 日。
- ^ 「依存性注入 |Professionalqa.com」。
- ^ 「依存性注入を使用する場合の欠点は何ですか?」。stackoverflow.com 。 2015年7月18日閲覧。
- ^ ab 「Dependency Injection Inversion – Clean Coder」。sites.google.com 。 2015年7月18日閲覧。
- ^ 「依存性注入フレームワークからアプリケーションを分離する」。InfoQ 。 2015年7月18日閲覧。
- ^ Martin Fowler (2004-01-23). 「Inversion of Control Containers と Dependency Injection パターン - Dependency Injection の形式」. Martinfowler.com . 2014-03-22に取得。
- ^ 「AccessibleObject (Java Platform SE 7)」。docs.oracle.com 。2015年7月18日閲覧。
- ^ Riehle, Dirk (2000)、「フレームワーク設計:ロールモデリングアプローチ」(PDF)、スイス連邦工科大学
- ^ 「依存性注入 != DI コンテナーの使用」www.loosecouplings.com 。 2015 年 7 月 18 日閲覧。
- ^ 「Black Sheep » DIY-DI » Print」. blacksheep.parry.org . 2015年6月27日時点のオリジナルよりアーカイブ。2015年7月18日閲覧。
- ^ 「Spring Tips: アノテーション付きの POJO は Plain ではありません」。2015 年 7 月 15 日時点のオリジナルよりアーカイブ。2015年 7 月 18 日閲覧。
- ^ 「POJO の注釈 – 恩恵か呪いか? | Techtracer」 2007 年 4 月 7 日。 2015 年 7 月 18 日閲覧。
- ^ Pro Spring Dynamic Modules for OSGi Service Platforms. APress. 2009-02-17. ISBN 9781430216124. 2015年7月6日閲覧。
- ^ 「Go 1.18 リリースノート - Go プログラミング言語」。go.dev 。 2024年4月17日閲覧。
- ^ 「Awesome Go – dependency injection」. Github . 2024年4月17日. 2024年4月17日閲覧。
外部リンク
- コンポジションルート by Mark Seemann
- 依存性注入の初心者向けガイド
- 依存性注入とテスト可能なオブジェクト: 疎結合でテスト可能なオブジェクトの設計 - Jeremy Weiskotten、Dr. Dobb's Journal、2006 年 5 月。
- デザイン パターン: 依存性の注入 -- MSDN マガジン、2005 年 9 月
- 依存性注入という用語を導入したマーティン・ファウラーのオリジナル記事
- EAA の P: プラグイン
- 依存性注入の背後にある豊かなエンジニアリングの伝統 ( Wayback Machineに 2008-03-13 にアーカイブ) - Andrew McVeigh - 依存性注入の詳細な歴史。
- 依存性注入とは何か? - 別の説明 - Jakob Jenkov
- 依存性注入でテストしやすいコードを書く -- Developer.com、2006 年 10 月 2008 年 3 月 11 日にWayback Machineにアーカイブ
- マネージ拡張フレームワークの概要 - MSDN
- Hunt 1998 による依存メカニズムの古い説明
- 依存性注入コンテナへのリファクタリング
- PHP における DI の理解
- 依存性注入コンテナは必要ありません
