JavaScriptでinterfaceを使ったポリモーフィズムを表現する

JavaScriptでinterfaceを使ったポリモーフィズムを表現する:

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クラスからはiBattleメソッドを削除しました。

hero.js
//iBattleメソッドを削除 
class Hero { 
    attack() { 
        console.log('勇者の攻撃!'); 
    } 
    speak(){ 
        console.log('勇者「Hello」'); 
    } 
} 
新たに定義したHeroクラスをインスタンス化したものを

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(); 
    } 
} 
JSはinterfaceを実装せずともポリモーフィズム的なことが出来るので今回書いた様な実装をするのはあまりないかなと正直思ってしまいました。

あとTypeScriptで書けば済むことでもあるので。

しかし、Java等のオブジェクト指向言語と同じ仕様で実装したいときに使えるかもしれません。

コメント

このブログの人気の投稿

投稿時間:2021-06-17 22:08:45 RSSフィード2021-06-17 22:00 分まとめ(2089件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)