pblog

pplog.net を作っている @ppworks こと越川直人(Koshikawa Naoto)のブログ。文体は日によって違う。esa LLCで働いてます(\\( ⁰⊖⁰)/)

Advanced ActionScript3.0 with Design Patternsの邦訳版を読んだメモ

ついに邦訳版が出ましたので、購入。 ActionScript 3.0 : デザインパターン (ADOBE TECH LAB) 薄い本なのでサラッと読めそうな気がします。読みながらのメモです。良く分からなかったので調べたこととかも書いておきます。 一部、訳が若干残念な感じなので英語版と一緒に読むことで理解が深まります。商売上手ですね。

ActionScript 3.0 : デザインパターン (ADOBE TECH LAB)
http://www.amazon.co.jp/dp/4798118362
Advanced ActionScript3.0 with Design Patterns
http://www.amazon.co.jp/dp/0321426568

** Chapter3 MVCパターン MVCについては、wikipediaとかに載ってます。

Model View Controller - Wikipedia
http://ja.wikipedia.org/wiki/Model_View_Controller

*** モデル - ビュー、コントローラからは独立 - モデル内のデータが変更された場合、変更メッセージをブロードキャストする -- as3で実装するには、モデルはデータが変更された際、Event.CHANGEをdispachするなど

*** ビュー - 視覚的な要素とモデルデータとを読み取るロジック - UIからの要求を処理するロジック - モデルへの参照を持つ

*** コントローラ - 入力処理を行う - モデルとビューを更新 - モデルへの参照を持つ - ユーザイベント、システムイベントを通じて、モデルのデータを変更する

図にするとこんな感じ MVCパターン

*** ClockDataの例(053) モデルでは、元データへの直接参照を避けるためにcloneメソッドを通してデータを受け取る直接オブジェクト参照をすると、モデル外での操作がデータモデルに影響してしまう。

|javascript| public function clone():Hoge { return new Hoge(); // 現在の状態の複製が必要な際はnewだけじゃだめだと思う } ||< Eventのハンドラを直接呼び出したい場合、ハンドラの引数の初期値をnullにしておく |javascript| public function Hoge() { addEventListener(Event.CHANGE, changeHandler);

changeHandler(); // 初回分を実行 }

private function changeHandler(event:Event=null):void {

} ||<

*** コントローラの追加の例(068)

自動で更新される時計の処理
  • モデルがシステムイベントで更新される。
  • ビューがそのイベントをリッスンしているのでビューが更新される
  • コントローラがそのイベントをリッスンしているので、コントローラに定義されているUIが更新される
ユーザが入力した時刻に更新される時計の処理
  • ユーザの入力でモデルを更新する
  • ビューがそのイベントをリッスンしているのでビューが更新される
  • コントローラがそのイベントをリッスンしているので、コントローラに定義されているUIが更新される(但し、ユーザの入力で既に変わっているの効果はない)

この例では、コントローラにUIのビューが混じっているので混乱しやすいかも知れません。私はもちろん混乱しました。

** Chapter4 シングルトンパターン

075の以下の文章の意味が分かりません。

ActionScript3.0のひとつの特徴は、メソッドのすべての引数は、デフォルト設定が不要であるというものがあります。

原文は

One feature of ActionScript 3.0 is that all parameters of a method are now required unless a default value is provided.

私の怪しい英語力で訳すと

|| ActionScript3.0では、メソッドの引数にデフォルト値がない場合、その引数は必須となる。 ||< といった感じですかね。それだと前後の文章が理解できます。

*** Settingsクラスの構築の例(081) flash.utils.Proxyクラスの使いどころを、これで知りました。未定義のプロパティやメソッドを捕捉するために使うわけですね。

*** コンポジション経由でEventDispatcherを追加(082) 他のクラスをすでに継承しているけど、あのクラス(EventDispatcher)の機能も欲しい!という場合の解決策です。

|javascript|

public class Hoge extends Fugo implements IEventDispatcher { private var _dispatcher:EventDispatcher;

public function Hoge() { _dispatcher = new EventDispatcher(); }

public function addEventListener(type:String, handler:Function, useCapture:Boolean, priority:int = 0, weakRef:Boolean = false):void { _dispatcher.addEventListener(type, handler, useCapture, priority, weakRef); }

// ... IEventDispatcherに必要なメソッドを実装 } ||<

** Chapter5 テンプレートメソッドパターンとファクトリーメソッドパターン この本で一番長い章です、タイトルが。 ActionScript3.0はasbstractがないので、抽象メソッド内で例外を発生させる方法がありますと書いてありますが例がないので、例はこんな感じ。

|javascript| package { public class AbstractClass { /* * constructor / public function AbstractClass() { if (Object(this).constructor == AbstractClass) throw(new Error("you can't create instance of AbstractClass.")); } } } ||< 本書で指摘されているように、これだと実行時にエラーを発生させるだけなんですよね。なので、命名規則をちゃんとして間違えてnewしちゃったらコンパイル時に気づいてね、みたいな感じで。

** Chapter6 プロキシパターン イメージローダの件が例として挙げられていますが、イメージの幅や高さはEvent.INITイベントが発生するまで取得出来ないので注意が必要です。(当たり前?)

*** flash.events.DataEventって何?

DataEvent オブジェクトは、生データのロードが完了したときにオブジェクトによって送出されます。 次の 2 種類のデータイベントがあります。 - DataEvent.DATA:送受信されたデータのために送出されます。 - DataEvent.UPLOAD_COMPLETE_DATA:データが送信され、サーバーが応答したときに送出されます。 flash.events.DataEventのasdoc

とのこと。このデザパタ本の中では下記のように使っています。

|javascript| dispatchEvent(new DateEvent(Event.COMPLETE, false, false, <<渡したいデータ>>); ||< これでhandler側から「渡したいデータ」にアクセス出来ます。私は普段、dispatchEventを送出する側にプロパティを持たせて、handler側からはevent.target.propertyNameを参照するようなやり方が多いです。でもこうやってデータ渡せるのは便利ですね。しかも組み込みイベント。どっかで使ってみたいと思います。

*** flash.utils.Proxy AS1, 2に存在したObjectクラスの_resolveメソッドは未定義オブジェクトの呼び出しを捕捉することが出来ました。 この機能はAS3から、flash.utils.Proxyに組み込まれました。flash.utils.Proxyクラスを継承することで未定義オブジェクトの呼び出しを捕捉します。 - 未定義プロパティの捕捉には、getPropertyメソッドをオーバーライドします。 - 未定義メソッドの捕捉には、callPropertyメソッドをオーバーライドします。

AS3では多重継承が出来ないため、Proxyクラスを継承したクラスで他のクラスも継承したい場合には、コンポジションによって機能を追加します。先の「コンポジション経由でEventDispatcherを追加」はこれです。

*** アダプタパターンとファサードパターン アダプタパターンは、対象のAPIを変換すること。ファサードパターンは、呼び出しを単純化することです。めもめも。

** Chapter7 イテレータパターン コレクションとイテレータの役割分担が大事。いままでちゃんと分けていなかったので反省です。

** Chapter8 コンポジットパターン インターフェースの実装を書く際に、毎回冗長なコードを書く可能性がある場合は、基本クラスを実装する。そして差分を継承先のクラスで書いていくようにしましょう。 インターフェースを使い始めのころは、まじめに1つ1つのメソッドを実装していて気づくのですが、共通部分があったりするんですよね。だったら、まずは抽象クラスで実装してそっから継承しようという話です。

ところで、126の以下の文章の意味が分かりません。

リーフエレメントはコンポジットエレメントになることができますが、コンポジットエレメントはリーフエレメントになることはできません。

原文は

Leaf elements can be placed in composite elements, but composite elements cannot be placed in leaf elements.

私の怪しい英語力で訳すと

|| リーフエレメントはコンポジットエレメントの中に配置できます。逆にコンポジットエレメントはリーフエレメントの中に配置出来ません。 ||< といった感じですかね。つまり逆の意味になってしまっていますので注意。

** Chapter9 デコレータパターン デコレートパターンは、「マトリョーシカ」に例えることが可能とはいえ、マトリョーシカって?

マトリョーシカ人形
http://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%88%E3%83%AA%E3%83%A7%E3%83%BC%E3%82%B7%E3%82%AB
Decoratorパターン
http://ja.wikipedia.org/wiki/Decorator_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3

本チャプターで登場する「デコレート」は原書では「Decorated」と書かれています。つまり、デコレータがデコレーションする対象を指します。デコレータがデコーレトをなんやかんやという記述が繰り返されていると何が何やら分からなくなりそうです。上記のwikipediaにある図のComponentが本書の「デコレートオブジェクト」に当たります。

** Chapter10 コマンドパターン

Command パターン
http://ja.wikipedia.org/wiki/Command_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3

CommandStackのputCommandでなぜspliceするのか疑問でしたが、nextメソッドとprevメソッドを見たら分かりました。prevとnextで_indexが変わるので、prevしている最中にputCommandした場合には、それ以降に存在していた履歴を全部消す必要がありますね。

図にすると、こんな感じ。 undoしてからputCommandしたらその先のコマンドは消す

本章後半にプロキシミティゲームの構築という節があるのですが、何故か理解できなくて何だろうと思っていたら、肝心なGameboardDataクラスの説明がすっぽり抜け落ちているではありませんか。各所に突然、GameboardDataクラスが登場していますが、定義が載っていません。

** Chapter11 メメントパターン - メメントオブジェクトにオリジネーターの状態を保存しておく - オリジネータにはメメントを取得・設定するメソッドを実装する必要がある

** Chapter12 ステートパターン

** Chapter13 イベント処理 イベント処理に関しては詳説 ActionScript 3.0を読んでおけば良い感じです。特筆することはありませんでした。

252の以下の表現がちょっと気になりました。

stopPropagation()はcurrentTargetのリスナへのイベント通知は終了させますが、それ以上のディスプレイリスト探索を中止します。

これは原文

If you call stopPropagation(), the event is not allowed to continue up the display list , but the currentTarget is allowed to finish dispatching the event to its listeners.

を直訳した感じなのですが、イベント通知は終了の意味がちょっと分かりづらいですね。

|| stopPropagation()はcurrentTargetに登録されたリスナへのイベント通知は送出します。但し、それ以降のイベントフローに存在するDisplayObject Listのイベント送出を中止します。 ||< という意味だと思います。

** Chapter14 データの転送

*** Flash Remoting NetConnectionを使う。call時の第二引数でRespoderインスタンスを指定することで、サービス側でreturnする値を受け取ることが可能。コールバック関数は - 正常なレスポンスを取得した際はResponder生成時の第一引数の関数 - サービス側に指定したメソッドがない場合などエラーが発生した際は、Responder生成時の第二引数の関数 が呼ばれる。

|javascript| var nc:NetConnection = new NetConnection(); nc.connect("<>"); nc.call("<>.<>", new Responder(result, error); // result, errorはコールバック ||<

** Chapter15 E4X E4Xに関しては詳説 ActionScript 3.0を読んでおけば良い感じです。特筆することはありませんでした。 意外なE4Xの使いどころといえば、CDATA SectionでJavaScript APIなんかもあります。

Chapter16 正規表現 * コンストラクタでのバックスラッシュ() コンストラクタでバックスラッシュ()を扱う場合、エスケープが必要となります。

|javascript| var regexp1:RegExp = new RegExp("^\d+$"); // \dという文字列でマッチ var regexp2:RegExp = new RegExp("^\d+$"); // \dは数値を表す文字クラスなので数値にマッチ var regexp3:RegExp = /^\d$/; // \dは数値を表す文字クラスなので数値にマッチ

||<

** 感想 デザインパターンの知識が多少なりともあるほうが読みやすいと思います。デザインパターンの書籍として以下のような書籍を読んでから望むと良いかもしれません。

増補改訂版Java言語で学ぶデザインパターン入門
http://www.amazon.co.jp/dp/4797327030
Head Firstデザインパターン―頭とからだで覚えるデザインパターンの基本
http://www.amazon.co.jp/dp/4873112494
PHPによるデザインパターン入門
http://www.amazon.co.jp/dp/4798015164

その他、AS3の知識ももちろん必要です。AS3の書籍は以下のものがおすすめです。

初めてのActionScript 3.0 Flashユーザーのためのステップアップガイド
http://www.amazon.co.jp/dp/4873113717
詳説 ActionScript 3.0
http://www.amazon.co.jp/dp/4873113873

** おまけ おれおれ正誤表を書いておきます。公式のものではないので参考程度にとどめて下さい。

*** 正誤表

|page|誤|正| |056|まず、Clockという抽象ベースクラス|まず、AbstractClockViewという抽象ベースクラス| |057|public function Clock|public function AbstractClockView| |066|date.milliseconds = getTimer().startTime;|date.milliseconds = getTimer() - startTime;| |070|view.y = 40.view.getBounds(view).top;|view.y = 40 - view.getBounds(view).top;| |075|ActionScript3.0のひとつの特徴は、メソッドのすべての引数は、デフォルト設定が不要であるというものがあります。|ActionScript3.0では、メソッドの引数にデフォルト値がない場合、その引数は必須となります。| |098|プロキシとしてLloaderを生成|プロキシとしてLoaderを生成| |126|リーフエレメントはコンポジットエレメントになることができますが、コンポジットエレメントはリーフエレメントになることはできません。|リーフエレメントはコンポジットエレメントの中に配置できます。逆にコンポジットエレメントはリーフエレメントの中に配置出来ません。| |144|public function ReaderDecorator|public function AbstractReaderDecorator| |145|extends ReaderDecorator|extends AbstractReaderDecorator(本書ではこうあるべきですが、DL出来るサンプルファイルはすべてReaderDecoratorになってます。)| |210|11.1.5.mailクラス|11.1.5 mainクラス| |252|stopPropagation()はcurrentTargetのリスナへのイベント通知は終了させますが、それ以上のディスプレイリスト探索を中止します。|stopPropagation()はcurrentTargetに登録されたリスナへのイベント通知は送出します。但し、それ以降のイベントフローに存在するDisplayObject Listのイベント送出を中止します。| |309|^ その行の先頭(mフラグ設定時)|^ mフラグ未設定時には文字列の先頭、mフラグ設定時にはその行の先頭| |309|$ その行の末尾(mフラグ設定時)|$ mフラグ未設定時には文字列の末尾、mフラグ設定時にはその行の末尾|

その他 |page|誤| |062|return value.toString();がインデントされていない| |115|UIntCollectionコンストラクタのindex = 0;がインデントされていない| |120|addElementメソッドブロックの終わりの}がインデントされていない| |191|GameboardDataクラスが突然登場するが紙面にGameboardDataクラスが掲載されていない| |196|private var pieces:Spriteが定義されていない|