コンストラクタ関数を動的に切り替える

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());
}
}

これですっきりする。寿司が食べたいなー。