Flasher向けデザインパターン-Null Objectパターン
最近ASデザインパターンの本が話題ですね。
そんなところで、開発中にでくわした改良のアイディアをパターンになぞらえて書いていこうかと思います。
AS3の開発でのボトルネックはエラー処理、とりわけ参照がNullであることによる例外をどうするかって場面だと思います。
Null Objectパターンをつかう
先ほどの案件で外部ファイルを読み込むにあたり、仮に読み込みが完了してなかったり、開発中で不足してるときにオブジェクトがない可能性を考えて作る必要がありました。
そういう場合はifステートメントで有無を確認して分岐したり、try...catch構文でエラーを回避したりしますが、可読性が落ちたり、いちいち書き換えることで手間や公開時に間違うリスクを増やすことになります。
if( se ) { se.play(); } // または例外をひろって停止するのはとりあえず防ぐ try{ se.play(); } catch(e:Error) { // }
そこで、結城さんのとこのNull Objectパターンを参考に、あらかじめ空のサウンドや、データオブジェクトをつくると分岐を書かなくてよくなります。
http://www.hyuki.com/dp/dpinfo.html#NullObject
厳密には最初の一回だけ有無を判断して、本来あってほしいオブジェクトと同じ操作ができる(例外が発生しない)オブジェクトを生成することになります。
//最初に判定。読み込みが失敗したりしたら行う処理 if( !se ) { se = new NullSound(); } //~~~~~~~~~ se.play(); //常にこの形で書ける
NullSoundはSoundクラスを継承したダミークラスでもいいですが、すべての処理を上書きするのはかえって面倒なので無音のサウンドをライブラリやEmbedで用意しましょう。
また同様に、システムが絡むときAPIから受け取ったXMLなどをデータオブジェクトとしてクラス定義しておけば、結合が先に行えない場合にダミー データを生成して利用したり、たとえばゲームの勝ち負けによる変化を擬似的に再現するなどしてデバッグを効率化することが可能になります。
// 通常 var gameResult:GameResult = new GameResult( loader.data ); // APIが実装されるまでのダミーデータ var gameResult:GameResult = new DummyGameResult(); // エラーが発生したときのフォローデータ try{ var gameResult:GameResult = new GameResult( loader.data ); } catch( e:Error ){ gameResult = new ErrorGameResult(); } // テスト用データ var gameResult:GameResult = new WinGameResult(); var gameResult:GameResult = new RandomGameResult(); //~~~~~~~ // ゲーム判定 場面 // ポイントの表示 pointField.text = gameResult.getPoint().toString(); if( gameResult.isWin() ){ //勝ったときの処理 } else{ //負けたときの処理 }
こうすることで、そのデータを利用するすべての場面に例外処理を書かなくてもよくなります。(厳密に言えばそうでは無いですが設計レベルの話で)
デザパタについて思うこと
個人的に、デザインパターンはこれさえあれば大丈夫!というような必殺技や特効薬ではないと考えています。ひとしきり考えた設計の裏づけであったり、考えるときのガイドライン、またそれらのアイディアのアイコンとして機能するものだと思います。
ASは先に設計してスムーズにいくケースが少なく、作ってみて考えることが多いので、実装してる途中で困ったとき、もっとスマートに実装できないかなーなんてときにパターンを利用するといった場面のほうが実際には多いし、効果的だと思います。そういう人は関連してリファクタリングの本もあわせ読みするとよいです。
またデザインパターンは建築用語でよくある設計構造をカテゴライズしてたフレームワークのようなもので、いわゆるGoFの23このパターン以外にもたくさんあるし、自分で考えたアイディアをパターン化してもいいっていうのも知っておくといいかも。
ほかにもProgressionやThreadなどのライブラリの設計もデザインパターンに当てはまる要素が多く見られるし、 ActionScript3.0のAPIそのものにもデザパタ的なエッセンスが見受けられるので、どうしてこういうつくりなのかな?って見方をするのも面白いですよ。