new 演算子を使用してクラスのインスタンスを作成する時、自動的にコンストラクタ関数が呼ばれる。そのコンストラクタ関数は当然 Function 型なので、new 演算子の後が Function 型の変数/定数でも良いわけだ。例えば、
var f:Function = String; var s:String = new f("hogehoge");
と書くことが出来る。ECMA スクリプトとして当たり前の動作なんだけど気づかなかった……。これをファクトリに適用してみた。
ファクトリを使って、ある特定のクラスのインスタンスを生成する場合はこんなコードになると思う。
とある寿司屋で、客がイクラを頼んだ。
var sushi:Sushi = sushiFactory.orderSushi("イクラ");
寿司職人は注文された寿司を握る。
//注文 public function orderSushi(sushiName:String):Sushi { var sushi:Sushi; sushi = createSushi(sushiName); return sushi; } //握る private function createSushi(sushiName:String):Sushi { if (sushiName == "マグロ") { return new Maguro(); } else if (sushiName == "イクラ") { return new Ikura(); } //その他の寿司ネタ }
これでも十分に機能するけれど、文字列で渡している sushiName を各寿司のコンストラクタ関数にしてしまうことで、ファクトリメソッドから if 文を取り除く事が出来る。
まず、客の注文を定数 IKURA に置き換えて、
var sushi:Sushi = sushiFactory.orderSushi(SushiFactory.IKURA);
寿司屋の定数に各寿司のコンストラクタ関数を保持し、createSushi メソッドを、引数のコンストラクタ関数で寿司が生成されるように変更する。
class SushiFactory { public static var MAGURO:Function = Maguro; public static var IKURA:Function = Ikura; //その他の寿司ネタやコンストラクタ //注文 public function orderSushi(sushiName:Function):Sushi { var sushi:Sushi; sushi = this.createSushi(sushiName); return sushi; } //握る private function createSushi(sushiName:Function):Sushi { return Sushi(new sushiName()); } }
これですっきりする。寿司が食べたいなー。