質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
DI (Dependence Injection)

DI (Dependence Injection)は、「依存性の注入」という概念を指します。オブジェクト間で依存性のあるコードを外部の設定ファイルから注入するソフトウェアパターン設計思想です。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

5760閲覧

DIコンテナの作り方について

退会済みユーザー

退会済みユーザー

総合スコア0

DI (Dependence Injection)

DI (Dependence Injection)は、「依存性の注入」という概念を指します。オブジェクト間で依存性のあるコードを外部の設定ファイルから注入するソフトウェアパターン設計思想です。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

1グッド

2クリップ

投稿2017/05/17 09:27

編集2017/05/17 09:38

単純な疑問なのですが、DIコンテナというのはどのように作るのでしょうか?

以下は普通にコンストラクタを通して依存性を注入するサンプルコードです。
※TypeScriptは長いこと書いていなかったので、間違っていたらすみません。。。

DIコンテナを作ると、コンストラクタの引数に依存するクラスのインスタンスを手動で渡してあげなくても、勝手にDIされる訳ですよね!?
それがどういう仕組みで実現されるのかがマジカルでわかりません。

このクラスにはこのクラスが依存するみたいなマッピングを、DIコンテナクラスみたいなところで行うのかなとは思ったりするのですが、どういう流れで依存先のクラスに自動で依存するクラスのインスタンスが注入されるのかがわかりません。

簡易的なものでも作れるようになれば理解が深まるとは思っているのですが、簡易的なものすら、どのように作ってよいやら。。。
ご存知の方がおりましたら、ご教授頂けるとありがたいです!

TypeScript

1interface Sendable { 2 3 send(): void; 4 5} 6 7 8class GmailSender implements Sendable{ 9 10 public send() { 11 12 console.log("send a gmail"); 13 14 } 15 16} 17 18 19class HotmailSender implements Sendable { 20 21 public send() { 22 23 console.log("send a hotmail"); 24 25 } 26 27} 28 29class Subject { 30 31 private mailer: Sendable; 32 33 constructor(mailer: Sendable) { 34 35 this.mailer = mailer; 36 37 } 38 39 public send() { 40 this.mailer.send(); 41 42 } 43 44} 45 46let sender = new GmailSender(); 47let subject = new Subject(sender); 48subject.send();
i50👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

コードはC#で悪いんだけども、コンストラクターインジェクションをベースに話をしよう。

まず、コンストラクターは情報さえあれば呼び出すことができる。
そこはわかってるかな?
C#やJavaはリフレクションができるから特にある型のインスタンス化は簡単にできる。
C++とかでも関数ポインタを集積すればそこを経由してインスタンス生成を間接的に行うことができる。
とにかく…最初に大事なことは、new 型名ってしなくても、情報からインスタンス化することは可能だってことだ。

そういう情報を集積して、取得したいクラスからその必要なパラメーター(子供)にわたって連結して値を生成できるように再帰呼び出しする仕組みを作るんだ。それが大体DIコンテナのやってることだ。

下記は、今、このページで打っただけだから下記のコードはぐだぐだだけども、一通り必要そうなコードを書いてみた。

C#

1// あるクラスのインジェクションに関係する情報を集める 2// これは関数で支持を出しても良いし、よりよい形ではリフレクションでも良い 3BindingInfo<T> Bind<T>() 4{ 5 // このコンストラクタにどんな情報があるかを事前にまとめておくためのクラスがあるとして 6 var info = new BindingInfo(typeof(T)); 7 8 // まずは器を用意しておく 9 cache[typeof(type)] = info; 10 11 return info; 12} 13 14// で、実装クラスの関連情報を作成した収集クラスに集める 15public class BindingInfo<T> 16{ 17 // 例えばある型と紐づける 18 public BindedTypeInfo To(Type type) 19 { 20 // 紐づける型が派生形であることを調べる 21 this.Type.IsAssignableFrom(type); 22 23 // C#だとこんな風にコンストラクタの一覧はとってこれるし 24 var constructors = type.GetConstructors(); 25 foreach (var constructor in constructors) 26 { 27 // ConstructorInfoからはGetParametersとかで引数はとってこれる 28 this.Add(new BindingConstructorInfo(constructor)); 29 30 // そもそも、ConstructorInfoは実行できる 31 // constructor.Invoke(/*引数はオブジェクトの配列*/); 32 } 33 } 34 35 // もしくはあるインスタンスと紐づけたり 36 public BindedTypeInfo ToConstant(T value) 37 { 38 // ここでは、この型情報のインスタンスが欲しい時に 39 // ここで受け取ったvalueを返すようにする 40 41 // で、紐づけられた関連情報を更にreturn することによって 42 // 細かいオプションを足せるようにしてもいいだろうね! 43 } 44} 45 46// DIコンテナで値を取得するときは、再帰的に生成を行っていく 47public T Get<T>() 48{ 49 // ある型の情報からインスタンスを取るために必要なものを考える 50 var info = cache[typeof(T)]; 51 // 例えばinfoがコンスタントならその値を返すだろうし 52 if (info.IsConstant) 53 { 54 return info.ConstantValue; 55 } 56 else 57 { 58 // じゃなくてインスタンスを生成しなければならないなら 59 // 必要なコンストラクタの引数を生成するために再帰的にGet<T>する 60 var constructor = info.GetConstructor(); 61 var parameters = new List<object>(); 62 foreach(var parameterInfo in constructor.GetParameters()) 63 { 64 // Getメソッドを再帰的に呼び出せばいつか端にたどり着く 65 parameters.Add(this.Get(parameterInfo.ParameterType)); 66 } 67 68 // で、生成したパラメータを使ってコンストラクタを実行する 69 return constructor.Invoke(parameters); 70 } 71}

情報を収集し、展開する。
収集方法は別にメソッドでもいいし、一般的なDIコンテナみたいになんらかのファイルでもいい。
基本は、あるインスタンスの生成方法を集積して、再帰的に呼ぶだけ。
インスタンス化できなければ情報不足として例外を投げればいい。

実行時の動作変更用のオプションの拡張、インスタンス化に関する情報のキャッシュで高速化だとか、まあそういう細かいのはいっぱいあるだろうと思う。

とりあえず… 既存のOSSのDIコンテナのソースを見よう!

#追記

上のクラスの使い方の想定をかいてなかったね。

C#

1var container = new MyDIContainer(); 2 3// ISomeClassという型には、ImplemetedClassをインスタンス化してよこせ、と指示を出す。 4container.Bind<ISomeClass>().To<ImplementedClass>(); 5 6var implemented = container.Get<ISomeClass>();

ちなみにこれはNinjectっていうC#のDIコンテナを僕が使っているのでその構造に強く影響を受けている。
NinjectはDIコンテナだけど設定ファイルを使わないので、その分プログラマーには直観的だと思う。
ymlだのXMLだので設定ファイルを書いてインジェクションするよりよっぽど使うのが簡単なので、発想はC#未経験でもページを見ればわかると思う。

設定ファイルを書くDIコンテナは、設定ファイルを読み込んで動作を変更できるようにちょっと変えただけだ。
設定ファイルを使う場合は、現在アプリケーションに読み込まれてる型情報をリフレクションで取得しておいて、その情報に設定ファイルから得たオプションを適用していく、という形になるだろうね。

投稿2017/05/17 11:26

編集2017/05/17 11:38
haru666

総合スコア1591

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/05/17 11:41

お〜!!!ご丁寧にコード付きの解説ありがとうございます!!!! > まず、コンストラクターは情報さえあれば呼び出すことができる。 そこはわかってるかな? C#やJavaはリフレクションができるから特にある型のインスタンス化は簡単にできる。 C++とかでも関数ポインタを集積すればそこを経由してインスタンス生成を間接的に行うことができる。 とにかく…最初に大事なことは、new 型名ってしなくても、情報からインスタンス化することは可能だってことだ。引用テキスト C#やJavaはリフレクションができるから特にある型のインスタンス化は簡単にできる。 C++とかでも関数ポインタを集積すればそこを経由してインスタンス生成を間接的に行うことができる。 とにかく…最初に大事なことは、new 型名ってしなくても、情報からインスタンス化することは可能だってことだ。 出だしから自分は理解できていないですが、一旦、リフレクションについて調べてみたりしながら、投稿頂いた回答を読み込んでみます! ありがとうございます!
haru666

2017/05/17 11:43 編集

ういーすー。質問の言語だと、Javaなんかがかなり作りやすいでしょう! 下記のQiitaでJavaのコンストラクタのリフレクションの話がでてます。 http://qiita.com/manahirosan/items/32da2cc9f5f03dc454ca 後は引数の型を生成するのを繰り返していけば、単純なDIコンテナは完成しますよ! …たぶんね!(僕は既製品しか使ってないから。笑)
退会済みユーザー

退会済みユーザー

2017/05/17 12:36

ありがとうございます。ちょっと読み込むのに時間かかりそうですが、有難く勉強させていただきます!
guest

0

DIコンテナのそもそもの目的は、コンストラクタインジェクションやセッターインジェクションにて、引数が多くなりすぎて、可読性やメンテナンスの部分で困ることを防ぐために、DI用のファイルで管理しませんかってことだと思います。

php

1public function __construct(Event $event,SomethingInterface $si, Sample $sp,・・・[いっぱいのインジェクション]){ 2 3}

例えば、symfonyだとymlに書いて、管理します。
DIコンテナはそんなにたくさんのインスタンスを返すとかの設計じゃないなら、必要ないかもしれません。作り方については、下記サイトが参考になるかと思います。
qiita

投稿2017/05/17 09:55

編集2017/05/17 09:55
imamoto_browser

総合スコア1161

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/05/17 09:59

小さい単位でクラス化していると、どうしてもDIするインスタンスが増えてしまうのですが、DIコンテナに興味を持っているのですが、簡易的な物を作って仕組みを理解したいところなのです。
退会済みユーザー

退会済みユーザー

2017/05/17 10:02

リンク先は見たことあるのですが、作り方というよりはDIの概要と既存のDIコンテナの使い方がちょろっとって感じの記事ですね。
imamoto_browser

2017/05/17 10:29

ymlを読んで、パースしてそれを元にクラスロードするコードを書けばいいのではないでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問