Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DI(依存性注入について)

Avatar for yuizho yuizho
November 21, 2015

 DI(依存性注入について)

Avatar for yuizho

yuizho

November 21, 2015
Tweet

More Decks by yuizho

Other Decks in Programming

Transcript

  1. 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()); } }
  2. 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(抽出方法) の実装クラス
  3. @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(); }
  4. @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オブジェクトが生成されま す。
  5. 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メソッドの結 果が正しいこと を確認するテストコードです。
  6. 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 のモックを返却するように上書きしている。
  7. 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()が呼ばれ た際に”テストコーヒー”が返却されるよ う設定。
  8. 代表的なDIコンテナ • Spring Framework • JavaEE (CDI) • Seasar2 •

    Zend Framework 2 • Dagger • Dagger2 • Proton • RoboGuice
  9. 言語とDIコンテナ • Javaなどの静的言語では色々と種類があるが、 RubyやPythonなどの動的言語ではあまり使われていない (と思う)。 私は一時DIについて関心を持って、いろいろ調べてみたし、 自分でDIコンテナ を実装してみたりもした。 でも、RubyでならDIコンテナがわずか20行で記述で きる上、

    よく考えてみたら、その20行も、なくてもほぼ同じことが簡単に実現で きることに気がついた時、 DIってのは硬直した言語のための技術なんだと気 がついた。 Matzにっき より http://www.rubyist.net/~matz/20091003.html