JavaScriptでinterfaceを使ったポリモーフィズムを表現する
JavaScriptでinterfaceを使ったポリモーフィズムを表現する:
JavaScriptのような動的型付け言語でinterfaceの型を指定して機能を限定する様な振る舞いをするコーディングを考えてみます。
TypeScriptを使えばすむのですが、素のJavaScriptでどうにか定義したいと思います。
RPGゲームを例にします。
下記は勇者を表すHeroクラスです。
Heroクラス内のattackメソッドはバトル中の物理攻撃
speakメソッドはフィールド移動中にキャラクターに話しかけるメソッドです。
バトル中はこのspeakメソッドを呼び出せない仕様にしたいです。
そこでiBattleメソッドを定義します。
iBattleメソッドは自分のclassが持つattackメソッドへの参照のみ定義したオブジェクトを返し、iBattleメソッドから返されたオブジェクトはspeakメソッドが呼び出せなくなります。
自分自身のクラスからではなく
他のオブジェクト指向言語のようにinterface用クラスを別クラスとして定義することを考えます。
下記のようにinterface作成用のIBattleクラスを作ります。
下記のようにHeroクラスからはiBattleメソッドを削除しました。
新たに定義したHeroクラスをインスタンス化したものを
iBattleクラスの引数に指定しattackしか出来ないインスタンスを作ります。
新たにHeroクラスにmagic(魔法)メソッドを追加し、attackメソッドとmagicメソッドのみ呼び出せるようにしてみます。
バトル中にmagicメソッドを呼び出せるようにするには
iBattleメソッドで返すmethod変数内のオブジェクトにmagicを追加します。
下記はダメな例かと思いますが載せておきます。
methodName配列の要素にメソッド名を追加したら、後はforEach内でreturn用のオブジェクトを変数method内に作ってくれます。
しかし、もっと良い書き方があるはずです。どなたか教えて下さい。
IBattleクラスからバトル中にmagicメソッドを呼び出せるようにするには
IBattleクラスのメンバメソッドにmagicを追加します。
JSはinterfaceを実装せずともポリモーフィズム的なことが出来るので今回書いた様な実装をするのはあまりないかなと正直思ってしまいました。
あとTypeScriptで書けば済むことでもあるので。
しかし、Java等のオブジェクト指向言語と同じ仕様で実装したいときに使えるかもしれません。
JavaScriptのような動的型付け言語でinterfaceの型を指定して機能を限定する様な振る舞いをするコーディングを考えてみます。
TypeScriptを使えばすむのですが、素のJavaScriptでどうにか定義したいと思います。
class内にinterface作成用メソッドを定義
RPGゲームを例にします。下記は勇者を表すHeroクラスです。
Heroクラス内のattackメソッドはバトル中の物理攻撃
speakメソッドはフィールド移動中にキャラクターに話しかけるメソッドです。
バトル中はこのspeakメソッドを呼び出せない仕様にしたいです。
そこでiBattleメソッドを定義します。
iBattleメソッドは自分のclassが持つattackメソッドへの参照のみ定義したオブジェクトを返し、iBattleメソッドから返されたオブジェクトはspeakメソッドが呼び出せなくなります。
hero.js
class Hero { attack() { console.log('勇者の攻撃!'); } speak(){ console.log('勇者「Hello」'); } iBattle(){ const method = { "attack": this.attack }; return method; } }
battle.js
//上記Heroクラスを使いバトル開始-------- const hero = new Hero(); //Heroインスタンス作成 const battleHero = hero.iBattle(); // attackだけ出来るinterfaceを作成 battleHero.attack(); // '勇者の攻撃!' battleHero.speak(); // エラーになる
interface作成用classを別に定義
自分自身のクラスからではなく他のオブジェクト指向言語のようにinterface用クラスを別クラスとして定義することを考えます。
下記のようにinterface作成用のIBattleクラスを作ります。
ibattle.js
class IBattle{ constructor(chara) { this.chara = chara; } attack() { this.chara.attack(); } }
hero.js
//iBattleメソッドを削除 class Hero { attack() { console.log('勇者の攻撃!'); } speak(){ console.log('勇者「Hello」'); } }
iBattleクラスの引数に指定しattackしか出来ないインスタンスを作ります。
battle.js
//上記Heroクラスをインスタンス化したものを //iBattleクラスの引数に指定しattackしか出来ないインスタンスにする const hero = new Hero(); const battleHero = new IBattle(hero); battleHero.attack(); // '勇者の攻撃!' battleHero.speak(); // エラーになる
複数メソッドが使えるinterfaceを定義
新たにHeroクラスにmagic(魔法)メソッドを追加し、attackメソッドとmagicメソッドのみ呼び出せるようにしてみます。
複数メソッドが使えるようにHeroクラスを修正した場合
バトル中にmagicメソッドを呼び出せるようにするにはiBattleメソッドで返すmethod変数内のオブジェクトにmagicを追加します。
hero.js
class Hero { attack() { console.log('勇者の攻撃!'); } speak() { console.log('勇者「Hello」'); } //magicメソッド追加 magic() { console.log('火炎じゅもんを唱えた!'); } iBattle() { const method = { "attack": this.attack, "magic": this.magic //magicを追加 }; return method; } }
methodName配列の要素にメソッド名を追加したら、後はforEach内でreturn用のオブジェクトを変数method内に作ってくれます。
しかし、もっと良い書き方があるはずです。どなたか教えて下さい。
hero.js
iBattle() { const methodName = ["attack", "magic"]; var method = {}; const self = this; methodName.forEach(function (element) { method[element] = self[element]; }); return method; }
複数メソッドが使えるようにIBattleクラスを修正した場合
IBattleクラスからバトル中にmagicメソッドを呼び出せるようにするにはIBattleクラスのメンバメソッドにmagicを追加します。
ibattle.js
class IBattle{ constructor(chara) { this.chara = chara; } attack() { this.chara.attack(); } //magicメソッド追加 magic() { this.chara.magic(); } }
あとTypeScriptで書けば済むことでもあるので。
しかし、Java等のオブジェクト指向言語と同じ仕様で実装したいときに使えるかもしれません。
コメント
コメントを投稿