JavaScriptでStrategyパターンを使ってみる

例えばアクションゲームではEasy, Normal, Hardといったゲームレベルを選択できますが、if文などで処理を切り分けてアルゴリズムを書いてしまうと、

  • 可読性が低く、メンテナンス性が悪い。
  • 既存ソース・コードへの影響が大きい。
  • 再利用することができない。

といった問題が生じてしまいます。

function run(level){

  if(level === HARD){
    //Hardモードに関する処理を記述
    ...
    execute();
  }else if(level === NORMAL){
    //Normalモードに関する処理を記述
    ...
    execute();
  }else if(level === EASY){
    //Easyモードに関する処理を記述
    ...
    execute();
  }
}

そこで、if文で切り替えるなど「何かの条件によって切り替わる可変処理」を外部カプセル化することで、これらの問題を解決する設計パターンをStrategyパターンといいます。

上記例のHARD, NORMAL, EASYでの処理は「何かの条件によって切り替わる可変処理」であるので、以下のようにactionオブジェクトで外部化してみます。

可変処理を外部化

//処理を実行する側
let action = {
  level : {},
  execute : function(level){
    level = this.level[level];
    if(level){
      level.execute();
    }else{
      console.log("LEVEL ERROR");
    }
  }
}

action.level.HARD = {
  execute : function(){
    console.log("HARDモードのアルゴリズム");
  }
}

action.level.NORMAL = {
  execute : function(){
    console.log("NORMALモードのアルゴリズム");
  }
}

action.level.EASY = {
  execute : function(){
    console.log("EASYモードのアルゴリズム");
  }
}

 

外部処理を利用する

//処理を利用する側
function run(level){
  action.execute(level);
}
run("HARD") //処理を実行 => "HARDモードのアルゴリズム"

 

処理を行う部分を外部化し(actionオブジェクト)、その処理を利用する部分(run())を切り分けることで、次のような利点があります。

例えば、NORMALモードで動かしたい場合には、

run("NORMAL");

とすればよいので、処理を利用する側としては実装がとてもシンプルになります。

一方でゲームのレベルに”Extra”モードを追加したい場合には、

action.level.EXTRA = {
  execute : function(){
    console.log("EXTRAモードのアルゴリズム");
  }
}

とactionオブジェクトに追加すればよく、メンテナンス性が保持され、より柔軟に変更を加えることができるようになることがわかるかと思います。

 

Strategyパターンは条件によって処理を切り替えたり、機能の追加・拡張があるような場合にはぜひとも利用したいデザインパターンです。

Related Posts