如果要用 AS3 動態建立物件其實很簡單:
public function createInstance(theClass:Class):* { return new theClass(); }
但是如果要建立的物件的類別建構子是有參數的話,要怎麼辦呢?
可以試著修改上面的 function:
public function createInstance(theClass:Class, args:Array):* { return new theClass(args); }
執行後就會發現,很抱歉,參數的數量不符合。
之前介紹過的 Parsley,她有一個 spicelib 的 Library ,裡面的 reflect package 裡有個 Constructor 可以用來動態建立有參數的類別。
用法如下:
var ci:ClassInfo = ClassInfo.forClass(Bar); var con:Constructor = ci.getConstructor(); var obj:Object = con.newInstance(["hello"]);
這樣就可以很方便的達成卡卡米想要的結果。
由於我很好奇她是怎麼做到的,所以就打開來看了一下 spicelib 的原始檔,結果發現是這樣寫的:
public static function createNewInstance (type:Class, params:Array) : Object { switch (params.length) { // Now this is really stupid. But there is no "Class.createInstance(args)" in AS3 case 0: return new type(); case 1: return new type(params[0]); case 2: return new type(params[0], params[1]); case 3: return new type(params[0], params[1], params[2]); case 4: return new type(params[0], params[1], params[2], params[3]); case 5: return new type(params[0], params[1], params[2], params[3], params[4]); case 6: return new type(params[0], params[1], params[2], params[3], params[4], params[5]); case 7: return new type(params[0], params[1], params[2], params[3], params[4], params[5], params[6]); case 8: return new type(params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7]); default: throw new IllegalArgumentError("Unsupported number of Constructor args: " + params.length); } }
就如同這篇所提到的一樣,AS3並沒有方法可以動態傳遞參數給類別的建構子,所以只能用上面的笨方法。
話說回來,動態建立物件時必須要指定類別,既然已經知道要建立何種類別了,似乎沒有必要透過這麼「搞剛」的方式。
我覺得比較有用的應該是透過類別名稱的字串來建立,例如需要建立的物件是透過外部的檔案(如 XML)來指定的。
這時候就可以利用 flash.utils.getDefinitionByName 來完成:
public function createInstance(className:String, ...args):* { // className 必須包含完整 package 名稱,例如 flash.display.Sprite var classRef:Class = getDefinitionByName(className) as Class; switch(args.length) { case 0: return new classRef(); // ... (略) default: throw new IllegalArgumentError("Unsupported number of Constructor args: " + args.length); } }
然後這樣使用:
// 建立 foo package 底下的 Bar 類別 var obj:Bar = createInstance("foo.Bar");
但是假如是用這樣的方式的話:
var obj:Object = createInstance("foo.Bar");
執行時就會出現 ReferenceError: Error #1065: 變數 Bar 未定義 的錯誤。原因在於編譯器不曉得要包含這個類別,所以無法動態建立。
解決的方法就是:
// 列出可能會被動態產生的類別 Bar; Bar2; var obj:Object = createInstance("foo.Bar"); var obj2:Object = createInstance("foo.Bar2");
沒有留言:
張貼留言