Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
DI(依存性注入について)
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
yuizho
November 21, 2015
Programming
530
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
Heart of Swift Concurrency
koher
0
1.2k
半永久的に提供し続けられるプライベートクラウドを目指して ― 利用者の認知負荷を抑えるAPI抽象化とハードウェア世代交代の基盤設計
tomokon
0
410
大喜利で理解するLLM as a Judge / Understanding LLM-as-a-Judge through Ogiri
rockname
0
190
技術的負債を組織課題として解く-増えすぎたマイクロサービスとの戦い-
reimaru
1
2.6k
Embedded Swiftで作る自作USBデバイス によるiOSデバイスの自動テスト / iOSDC Japan 2026 glassfiber
glassfiber
0
270
Starting & Sustaining Code-Based E2E Testing for Non-Coding QA Teams( #jasstniigata )
teyamagu
PRO
1
860
Vue Fes Japan 2026 タイムテーブル徹底解説
448jp
1
590
Workers Cache を知る
syumai
0
320
WebRTC映像をAirPlayに対応させる挑戦.pdf
monolithic_adam
0
330
そのリトライ、死んだコネクションを使い回していませんか ── GoのHTTPクライアントとHTTP/2を実プロダクト障害から学び直す
myus4a
0
380
JAWS-UG 東京支部が始める、JAWS-UG支部コラボ / JAWS-UG lunchtime LT Collaboration
y0hgi
0
180
仕様駆動開発による爆速プロダクト開発 / Bakusoku Spec Driven Development
kobakei
0
170
Featured
See All Featured
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
1k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.7k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
8k
Ten Tips & Tricks for a 🌱 transition
stuffmc
1
250
Joys of Absence: A Defence of Solitary Play
codingconduct
1
530
Docker and Python
trallard
47
4.2k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
320
It's Worth the Effort
3n
188
29k
We Have a Design System, Now What?
morganepeng
55
8.3k
Fashionably flexible responsive web design (full day workshop)
malarkey
409
67k
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
550
Discover your Explorer Soul
emna__ayadi
2
1.3k
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すればいいってもんでもない。
ご清聴ありがとうございました