40歳からのキャリアチェンジ

20代はエンジニア・PM、30代はWeb系エンジニア向けのキャリアアドバイザー。40代の今はフリーランスで開発含めて色々やってます。技術ネタとしてはRuby/RailsとJavaScript関連あたり

マリオでStateパターン! 〜JavaScript編〜

先日書いたエントリ

現在のページ数チェックとどのボタンクリックしたのか判定しているため基本同じようなコードが存在して、スパゲッティコードになりそうなので、この部分の設計をしっかりしておかないと、後々大変になりそうなので、ここはちょっとじっくり考えることにします。

と書きました。

定期購読しているWEB+DB PRESSVol.53の特集1の記事(JavaScript/Flash/HTML 5 でスパゲッティコードにならないためのモダン設計入門)のことがなんとなく頭の中にあったからこう感じたのかもしれません。

改めてWEB+DB PRESSを読み返した後に、関連しそうな情報を色々ネットで調べる中で

「イベントドリブンなアプリケーションの設計する上でGoFデザインパターンを適用すればスッキリしたコードになりそう」

と感じたのですが、Stateパターン、Strategyパターン、Observerパターンのどれを適用すれば良いのか正直よくわからない・・

こういうのは実際にコード書きながら考えるほうが良いのかと思って、関連する情報を探している中で、マリオでStateパターン! 〜Java編〜を見つけたので、Stateパターンの理解をするためにまずはJavaScript編を自分で実装してみることにしました。

実際のコード

Javaは全くコード書いたことないですが、MarioStateインタフェースと、その実装のDefaultMario、BigMario、FireMario などの関係はなんとなく理解できました。

一部本家(?)と違うけれど、とりあえずこんな感じのコードになり、GoogleChromeの開発ツールで実行したら一応意図したように動作しました。

mario

var DefaultMario = function(){};
DefaultMario.prototype ={
  eatMushroom:function(){
    console.log('状態遷移(アクション) ---> きのこを食べた!');
    return new BigMario();
  },
  eatFlower:function(){
    console.log('状態遷移(アクション) ---> フラワーを食べた!');
    return new BigMario();
  },
  damage:function(){
    console.log('gama over!!');
  },
  sayState:function(){
    console.log('this is default mario');
  }
};

var BigMario = function(){};
BigMario.prototype ={
  eatMushroom:function(){
    console.log('状態遷移(アクション) ---> きのこを食べた!');
    return new BigMario(); // return true??
  },
  eatFlower:function(){
    console.log("状態遷移(アクション) ---> フラワーを食べた!");
    return new FireMario();
  },
  damage:function(){
    console.log("状態遷移(アクション) ---> ノコノコに当たった!");
    return new DefaultMario();
  },
  sayState:function(){
    console.log('this is Big mario');
  }
};

var FireMario = function(){};
FireMario.prototype = {
  eatMushroom:function(){
    console.log('状態遷移(アクション) ---> きのこを食べた!');
    return new FireMario(); // return true??
  },
  eatFlower:function(){
    console.log("状態遷移(アクション) ---> フラワーを食べた!");
    return new FireMario(); // return true??
  },
  damage:function(){
    console.log("状態遷移(アクション) ---> ノコノコに当たった!");
    return new BigMario();
  },
  sayState:function(){
    console.log('this is Fire mario');
  }
};

var Mario = function(){
  // きのこを食べる
  this.EVENT_EAT_MUSHROOM = 0;
  // フラワーを食べる
  this.EVENT_EAT_FLOWER = 1;
  // ノコノコニ当たる
  this.EVENT_DAMAGE = 2;
  // 状態を表す
  this.state = new DefaultMario();
};
Mario.prototype = {
  sayState:function(){
    return this.state.sayState();
  },
  adventures:function(){
    console.log('game start');
     // 初期状態を言う
    this.sayState();
    // 本家では、ここは乱数使って数値を生成しているが、手抜きでこうしました
    var gameevent = [0,1,2,1,1,2,2,2];
    for(var i =0;i<gameevent.length;i++){
       if (this.EVENT_EAT_MUSHROOM == gameevent[i]) {
         this.state = this.state.eatMushroom();
       } else if (this.EVENT_EAT_FLOWER == gameevent[i]) {
         this.state = this.state.eatFlower();
       } else if (this.EVENT_DAMAGE == gameevent[i]) {
         this.state = this.state.damage();
       } else {
         console.log("ここはありえなーいw");
       }
    }
  }
};

var Game = new Mario();
Game.adventures();

実際に手を動かしてみて、Stateパターンの概念はわかった気がしてきました。これをベースに自分がつくっているアプリケーションでもStateパターンが適用できそうか考えてみます

WEB+DB PRESS Vol.53
WEB+DB PRESS Vol.53
posted with amazlet at 11.05.16
WEB+DB PRESS編集部
技術評論社
売り上げランキング: 183781