Dependency Injectionとは
-
Upload
hidenori-doi -
Category
Engineering
-
view
246 -
download
0
Transcript of Dependency Injectionとは
Dependency Injectionとはdoi
依存とはDependency
依存とは• 僕はパソコンが無いと生きていけない
• 僕はパソコンに依存
• ネットがないと僕は生きていけない
• 僕はネットとパソコンが無いと成立しない状態
例えば
Codeclass Enemy { int hp; public void damage(int damage) { hp -= damage; } }
class Boss { int hp; public void damage(int damage) { hp -= damage; } }
class Player { public void attackEnemy(Enemy enemy) { enemy.damage( 10 ); } public void attackBoss (Boss boss) { boss.damage( 10 ); } }
Codeclass GameManager { Player player; Enemy enemy; Boss boss;
public void start() // ゲーム開始時に一度だけ呼ばれる { player = new Player(); enemy = new Enemy(); boss = new Boss(); }
public void update() { if (KeyDown( A_BUTTON )) // Aボタンが押されていたら player.attackEnemy( enemy ); if (KeyDown( B_BUTTON )) // Aボタンが押されていたら player.attackBoss( boss ); } }
クラス図Player は Enemy と Boss に依存してる
依存の影響
Open-Closed Principle
“オープン・クローズドの原則”
敵を増やそうマジシャン、狂熊、ワルガキ 凶悪でかっこいいモンスターのアイデアがじゃぶじゃぶ湧き出る…!!
Codeclass Player { public void attackEnemy(Enemy enemy) { enemy.damage( 10 ); } public void attackBoss(Boss boss) { boss.damage( 10 ); } public void attackMagician(Magician magician) { magician.damage( 10 ); } public void attackWarBear(WarBear warBear) { warBear.damage( 10 ); } public void attackBadBoy(BadBoy badBoy) { badBoy.damage( 10 ); } }
クラス図Player はいろんな敵を知っている状態じゃないと成立しない
依存を減らしたい
• Playerの他者への依存は膨らむばかり
• 依存をなんとか減らせないか
共通のインターフェイス• クラスの持つべき性質をルール化する • 基底クラス
• C# の interface, C++なら多重継承
• Duck Typing
• ルールを決める手段は言語や処理系によって様々
• ルール:ダメージを受けることができる
damage()
Interface// ルールの規定 interface ILife { function damage(int value); }
// ルールに基づく実装 class Enemy implements ILife { var hp = 10; public function damage(int value) { hp -= value; } }
Playerはシンプルにclass Player { // ILife インターフェイスを持つ相手ならだれでも public void attack(ILife target) { target.damage( 10 ); // damage()を与えちゃうよ } }
敵がいくら増えてもclass Boss implements ILife { int hp = 100; public void damage(int value) { hp -= value/2; } }
class Magician implements ILife { int hp = 5; public void damage(int value) { hp -= value; } }
class BadBoy implements ILife { int hp = 99; public void damage(int value) { hp -= value; } }
Playerは影響を受けないclass Player { // ILife インターフェイスを持つ相手ならだれでも public void attack(ILife target) { target.damage( 10 ); } }
クラス図インターフェイスを知っていれば 具体的な相手は知らなくて良い
良くなったこと• 意識することが減る
• 敵を作ったら damage っていう関数を必ず作って、Playerにその敵専用の攻撃メソッドを追加するの忘れないでね
• ILifeのインターフェイス実装しといて
良くなったこと• コンパイル時間の低下
• 敵のロジック修正するたびにPlayerが再コンパイルされる
• 変更した敵のファイルだけ再コンパイルされる
インターフェース• チーム開発、大規模開発において重要な考え方
• 技術仕様のコード化
• テストが書きやすくなる
OCP• 拡張をしても、他のモジュールへ影響を与えない
• 新しい敵を追加しても Player は影響を受けない
• Player のロジックを変更しても敵は影響を受けない
ちょっと寄り道class GameManager { Player player; Enemy enemy; // implements ILife Boss boss; // implements ILife
public void start() // ゲーム開始時に一度だけ呼ばれる { player = new Player(); enemy = new Enemy(); boss = new Boss(); }
public void update() // 毎フレーム呼ばれる { if (KeyDown( A_BUTTON )) // Aボタンが押されていたら player.attack( enemy ); if (KeyDown( B_BUTTON )) // Bボタンが押されていたら player.attack( boss ); } }
こいつ何者?• 役割の明確でないクラス名
• インスタンスの生成・ゲームロジック・入力処理。なんでも屋。
• ゲームに出てくるクラスを全部知っているつまり、すべてのクラスに依存している
• 世界を知るもの
依存注入とはDependency Injection
新仕様
プレイヤーは武器を装備できて敵を攻撃できるんだよ
Codeclass Weapon { public int power() { return 10; } // 攻撃力 }
class Player { public void attack( ILife enemy ) { Weapon weapon = new Weapon(); enemy.damage(weapon.power); } }
新仕様
新しくて、かっこ良くて、強い武器が思いついてしまうんだ…!
Interfaceinterface IWeapon { int power() // 攻撃力 }
class SuperSword implements IWeapon { public int power() { return 9999; } // 攻撃力 }
class BigGreatAxe implements IWeapon { public int power() { return 100; } // 攻撃力 }
class HyperUltimateKnife …
Playerclass Player { IWeapon weapon;
public void equip( int type ) { switch(weaponType) { case 1: weapon = new SuperSword(); break; case 2: weapon = new BigGreatAxe(); break; case 3: weapon = new HyperUltimateKnife(); break; } }
public void attack( ILife enemy ) { enemy.damage( weapon.power() ); } }
クラス図Playerがすべての武器に依存してるぞ…
依存を絶つ
Player に誰かが武器を渡してあげる (Inject)
依存注入のパターンclass Player { IWeapon equipedWeapon;
Player( IWeapon weapon ) { equipedWeapon = weapon; }
public void setWeapon( IWeapon weapon ) { equipedWeapon = weapon; }
public function attack( ILife enemy ) { enemy.damage( equipedWeapon.power() ); }
/* こんな書き方も */
public void setWeaponAndAttack( ILife enemy, IWeapon weapon ) { enemy.damage( weapon.power ); } }
Constructor Injection Player( IWeapon weapon ) { equipedWeapon = weapon; }
Setter Injection public void setWeapon( IWeapon weapon ) { equipedWeapon = weapon; }
Interface Injectionpublic void setWeaponAndAttack( ILife enemy, IWeapon weapon ) { enemy.damage( weapon.power ); }
クラス図Player は インターフェイスのみに依存
また寄り道class GameManager { Player player; Enemy enemy; Boss boss; Weapon weapon;
public void start() // ゲーム開始時に一度だけ呼ばれる { weapon = new Weapon(); player = new Player( weapon ); // 依存の注入 Constructor Injection enemy = new Enemy(); boss = new Boss(); }
public void update() { if (KeyDown( A_BUTTON )) // Aボタンが押されていたら player.attack( enemy ); if (KeyDown( B_BUTTON )) // Bボタンが押されていたら player.attack( boss ); } }
何が起きているか• Player はインターフェイスさえ知っていれば、どんな武器でも使いこなせるし、どんな敵にも攻撃できるようになった
• 敵をじゃぶじゃぶ追加できるようになった
• 武器をじゃぶじゃぶ追加できるようになった
• GameManagerという謎のクラスがすべての武器とすべての敵に依存している
次回DIコンテナについてやります