Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
DI(依存性注入について)
Search
yuizho
November 21, 2015
Programming
520
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
DI(依存性注入について)
yuizho
November 21, 2015
More Decks by yuizho
See All by yuizho
サーバ構築を自動化する~Ansible ~
yuizho
1
130
Other Decks in Programming
See All in Programming
2年かけて Deno に DOMMatrix を実装した話 / How I implemented DOMMatrix in Deno over two years
petamoriken
0
210
仕様駆動開発へのトライを機に チームに適合する手法を模索し続けている話
freee
PRO
0
500
わからない話を追いかけたら、プログラミング言語を作る側にいた
ydah
3
500
5分で問診!Composer セキュリティ健康診断
codmoninc
0
1k
関東Kaggler会_NVIDIA_Nemotron_コンペ_振り返り
rick_ds
0
560
【やさしく解説 設計編・中級 #4】ルールの寿命と、システムの年輪
panda728
PRO
2
190
為什麼你並不需要ViewModel / No, you don't need a ViewModel
lovee
1
490
Built Our Own Background Agent at LayerX
layerx
PRO
10
5.4k
AI時代のPHPer生存戦略 ~「言語、もうなんでもよくない?」に本気で向き合う~
vivion
0
400
SlackアプリとLambdaの 連携を構築した話
pawn_4_s
1
120
進化を続けるGo toolsの現在地 / The Current State of Ever-Evolving Go Tools
hond0413
0
210
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
180
Featured
See All Featured
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
390
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
400
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
640
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
940
How Software Deployment tools have changed in the past 20 years
geshan
1
34k
Producing Creativity
orderedlist
PRO
348
40k
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
280
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
Claude Code のすすめ
schroneko
67
230k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.4k
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
520
Transcript
DI(依存性注入)について 伊藤 結
ところで、DIと聞いて ピンとくる方はいますか?
DI(依存性注入)とは なるほど。わからん。 依存性の注入(英: Dependency injection)とは、コンポーネント間の依存関係をプロ グラムのソースコードから 排除し、外部の設定ファイルなどで注入できるようにするソ フトウェアパターンである。英語の頭文字からDIと略される。 wikipediaより https://ja.wikipedia.org/wiki/依存性の注入
DI(依存性注入)とは 依存性の注入(英: Dependency injection)とは、コンポーネント間の依存関係をプロ グラムのソースコードから 排除し、外部の設定ファイルなどで注入できるようにするソ フトウェアパターンである。英語の頭文字からDIと略される。 wikipediaより https://ja.wikipedia.org/wiki/依存性の注入 言葉の意味から考えてみよう!
依存性ってなに?
public class Siphon implements BrewingMethod { @Override public String brew()
{ return "サイフォンでいれたコーヒー "; } } public class CoffeeShop { public String brewCoffee() { BrewingMethod siphone = new Siphone(); return siphone.brew() + "が出来上がりました [_]P"; } } public class CoffeeShopApp { public static void main(String... args) { CoffeeShop coffeeShop = new CoffeeShopApp(); System.out.println(coffeeShop.brewCoffee()); } }
public class Siphon implements BrewingMethod { @Override public String brew()
{ return "サイフォンでいれたコーヒー "; } } public class CoffeeShop { public String brewCoffee() { BrewingMethod siphone = new Siphone(); return siphone.brew() + "が出来上がりました [_]P"; } } public class CoffeeShopApp { public static void main(String... args) { CoffeeShop coffeeShop = new CoffeeShopApp(); System.out.println(coffeeShop.brewCoffee()); } } プログラムの実行クラス BrewingMethod(抽出方法) の実装クラス
クラスAからクラスBを直接インスタンス化している時、 クラスAはクラスBがないと動きません。 このような状態は クラスAとクラスBが依存関係にある、 クラスAはクラスBに依存しているといえます。 今回の例でいうと、 CfeeShopAppとCoffeeShop CoffeeShopとSiphone の間で依存関係があるということになります
注入ってなに?
実際のコードで説明します
DIコンテナを使って、 実際にDIをやってみよう!
DIコンテナとは • すごく簡単に言うと、「XXにこのクラスのオブジェクトを注入してね」 という設定を書いておくとDI(依存性の注入)を実行するよくんのこと。 今回はJava向けのDaggerというDIコンテナを使います。
@Module(injects = CoffeeShopApp.class) public class BrewingMethodModule { @Provides public BrewingMethod
provideBrewingMethod() { return new Siphon(); } } public class CoffeeShop { // Siphonオブジェクトが注入される @Inject BrewingMethod brewingMethod; .... } public class CoffeeShopApp { //兄弟クラスがないので設定なしで CoffeeShopオブジェクトが注入される @Inject CoffeeShop coffeeShop; public void run() { System.out.println(coffeeShop.brewCoffee()); } public static void main(String... args) { // Daggerのオブジェクト生成(設定を読み込んで、各オブジェクトが注入された CoffeeShopAppオブジェクトを生成) ObjectGraph objectGraph = ObjectGraph.create(new BrewingMethodModule()); CoffeeShopApp coffeeShopApp = objectGraph.get(CoffeeShopApp.class); coffeeShopApp.run(); }
@Module(injects = CoffeeShopApp.class) public class BrewingMethodModule { @Provides public BrewingMethod
provideBrewingMethod() { return new Siphon(); } } public class CoffeeShop { // Siphonオブジェクトが注入される @Inject BrewingMethod brewingMethod; .... } public class CoffeeShopApp { //兄弟クラスがないので設定なしで CoffeeShopオブジェクトが注入される @Inject CoffeeShop coffeeShop; public void run() { System.out.println(coffeeShop.brewCoffee()); } public static void main(String... args) { // Daggerのオブジェクト生成(設定を読み込んで、各オブジェクトが注入された CoffeeShopAppオブジェクトを生成) ObjectGraph objectGraph = ObjectGraph.create(new BrewingMethodModule()); CoffeeShopApp coffeeShopApp = objectGraph.get(CoffeeShopApp.class); coffeeShopApp.run(); } @Moduleで注入先クラスを指定 @Providesを付与したメソッドで、注入するオ ブジェクトを生成する処理を記述。 Daggerライブラリのオブジェクト生成処理 (BrewingMethodModuleの設定を読み込 んで、CoffeeShopAppオブジェクトを生 成)。 @Injectが付与されている CofeeShopApp#cofeeShop, CofeeShop#resingMethod にオブジェクトが注入された状態の CoffeeShopAppオブジェクトが生成されま す。
Daggerが依存性が注入されたオブジェクトを生成することで、 CofeeShopAppから直接インスタンス化する記述をなくすことができ、 以下のモジュール間の依存関係を外部に逃がすことができました。 CofeeShop ー Siphon CoffeeShopApp ー CofeeShop
で、DI使うと なにがよくなるの?
DIを使う場合の利点 • モジュール間の依存関係を弱めることができる (保守性が高まる) • 単体テストが楽になる (Aモジュールが完成する前にBモジュールをテストできる、外から特定のモジュールをモック に差し替えることができる) 実際やってみて、特にテストコードを書くとき、Mockオブ ジェクトに差し替えてテストながせるのが心地よかったで
す。
public class CoffeeShopTest { @Inject CoffeeShop coffeeShop; @Inject BrewingMethod brewingMethod;
@Before public void setUp() { ObjectGraph.create(new TestModule()).inject(this); } @Module(includes = BrewingMethodModule.class, injects = CoffeeShopTest.class, overrides = true) static class TestModule { @Provides @Singleton public BrewingMethod provideBrewingMethod() { return Mockito.mock(BrewingMethod.class); } } @Test public void testBrewCoffee() { Mockito.when(brewingMethod.brew()).thenReturn("テストコーヒー"); String result = coffeeShop.brewCoffee(); Mockito.verify(brewingMethod, Mockito.times(1)).brew(); assertThat(result, is("テストコーヒーが出来上がりました [_]P")); } DIを利用したテストコードの一例 CoffeShopのテストコードです。 BrewingMethodクラスのオブジェクトは モックに置き換えてテストを実行してい ます。 CoffeeShopから BrewingMethod#brewメソッドが1回呼 ばれていること、 CoffeeShop#brewCoffeeメソッドの結 果が正しいこと を確認するテストコードです。
public class CoffeeShopTest { @Inject CoffeeShop coffeeShop; @Inject BrewingMethod brewingMethod;
@Before public void setUp() { ObjectGraph.create(new TestModule()).inject(this); } @Module(includes = BrewingMethodModule.class, injects = CoffeeShopTest.class, overrides = true) static class TestModule { @Provides @Singleton public BrewingMethod provideBrewingMethod() { return Mockito.mock(BrewingMethod.class); } } @Test public void testBrewCoffee() { Mockito.when(brewingMethod.brew()).thenReturn("テストコーヒー"); String result = coffeeShop.brewCoffee(); Mockito.verify(brewingMethod, Mockito.times(1)).brew(); assertThat(result, is("テストコーヒーが出来上がりました [_]P")); } BrewingMethodModuleを、BrewingMethod のモックを返却するように上書きしている。
public class CoffeeShopTest { @Inject CoffeeShop coffeeShop; @Inject BrewingMethod brewingMethod;
@Before public void setUp() { ObjectGraph.create(new TestModule()).inject(this); } @Module(includes = BrewingMethodModule.class, injects = CoffeeShopTest.class, overrides = true) static class TestModule { @Provides @Singleton public BrewingMethod provideBrewingMethod() { return Mockito.mock(BrewingMethod.class); } } @Test public void testBrewCoffee() { Mockito.when(brewingMethod.brew()).thenReturn("テストコーヒー"); String result = coffeeShop.brewCoffee(); Mockito.verify(brewingMethod, Mockito.times(1)).brew(); assertThat(result, is("テストコーヒーが出来上がりました [_]P")); } 本クラスへの依存性注入の実行 CoffeeShop#brewingMethod、 brewingMethodへ BrewingMethodのMockを注入する。 (TestModule#provideBrewingMethodに Singletonアノテーションを付与しているので すべて同じオブジェクトが注入される)。 注入した、モックオブジェクトの振る舞 いを設定して、テストを実行。 ※BrewingMethod#brew()が呼ばれ た際に”テストコーヒー”が返却されるよ う設定。
DIコンテナって 他にはどんなのがあるの?
代表的なDIコンテナ • Spring Framework • JavaEE (CDI) • Seasar2 •
Zend Framework 2 • Dagger • Dagger2 • Proton • RoboGuice
なんかJavaばっかりじゃね?
言語とDIコンテナ • Javaなどの静的言語では色々と種類があるが、 RubyやPythonなどの動的言語ではあまり使われていない (と思う)。 私は一時DIについて関心を持って、いろいろ調べてみたし、 自分でDIコンテナ を実装してみたりもした。 でも、RubyでならDIコンテナがわずか20行で記述で きる上、
よく考えてみたら、その20行も、なくてもほぼ同じことが簡単に実現で きることに気がついた時、 DIってのは硬直した言語のための技術なんだと気 がついた。 Matzにっき より http://www.rubyist.net/~matz/20091003.html
どんな所でDIを使うべき?
DIの使いどころ • (当たり前ですが) DIを前提にしたフレームワークを使用するとき。 • Javaを使用しており、テスト駆動開発 (TDD)とかテストコードを書くことが前提のプロジェクト。 • 実装があるモジュールに依存してるが、そのモジュールは未完成、でも単体テストを始めない といけないんだよ〜みたいなことになりそうなとき。
採用したときのコスト(学習コストなど)に比べて、モ ジュール間の依存関係を弱めることが重要な時に使用 するべき。 何でもかんでもDIすればいいってもんでもない。
ご清聴ありがとうございました