AS3 - 使用实际类名的参数化工厂方法

时间:2011-01-05 15:37:32

标签: actionscript-3 factory-pattern dynamic-class-creation

而不是使用硬编码的switch语句,在其中传递类的字符串名称然后实例化相应的类,我想将类的实际名称传递给我的工厂方法并动态地使用它创建该类的实例。我认为这将是微不足道的,我很惊讶它不起作用。我必须遗漏一些非常基本的东西:

示例代码:

createProduct(50, "Product1Class");
createProduct(5, "Product2Class");


private function createProduct(amount:uint, productClassName:String):void {
    var productReference:Class;
    try {
        productReference = getDefinitionByName(productClassName) as Class;

        for (var i:uint = 0; i < amount; i++) {
        var product = new productReference() as ProductBaseClass; // throws reference error!
        }
    } catch (error:ReferenceError) {
        throw new ReferenceError(error.message + " Have you linked a library item to this class?");
    }
 }

唯一可能有点奇怪(不确定)的是这些“产品”实际上是链接的库项目(即:我在库中有一个movieClip,它与Product1Class有联系,另一个与Product2Class有联系扩展ProductBaseClass,后者又扩展了MovieClip。

为什么是ReferenceError?

3 个答案:

答案 0 :(得分:1)

如果你有一个运行时加载的库,那么Class不会被编译到主swf中,所以当你尝试创建它们时会得到运行时引用错误。

要解决此问题,您可以声明要编译的类的“虚拟”变量,或者如果使用flex编译器,则可以选择包含您缺少的类。

e.g。在项目的任何地方声明这些

private var p1:Product1Class;
private var p2:Product2Class;

这是一个令人沮丧的问题,如果您的类扩展了MovieClip,这是一个动态类,您可以通过执行以下操作来访问属性等:

var product:MovieClip = new productReference() as MovieClip;
p1["someCustomProperty"]; //Dot notation might work here as it is a dynamic class

答案 1 :(得分:1)

Chris绝对正确,在调用getDefinitionByName期间实际上抛出了ReferenceError,这意味着反射方法在您的应用程序域中找不到Product1ClassProduct2Class。您可以通过直接检查应用程序域来检查定义是否可用,例如:

// inside your createProduct method, yields 'false'.
ApplicationDomain.currentDomain.hasDefinition( productClassName );

这些库资产是否在运行时加载?如果是这样,您可以通过向Loader添加适当配置的LoaderContext来确保库swf已加载到当前应用程序域中,或者您可以使用加载的swf应用程序替换对getDefinitionByName的调用域的getDefinition方法。

答案 2 :(得分:1)

getDefinitionByName()和ApplicationDomain.currentDomain.hasDefinition()需要完全限定类名。当Product1Class和Product2Class在默认包中时,原始帖子中的示例代码有效。但是,如果将产品类移动到另一个包,则必须确保为getDefinitionByName()提供完全限定的类名。

因此,如果我们将产品类放在com.example.products中,那么调用将变为:

productReference = getDefinitionByName("com.example.products.Product1Class") as Class;

我不确定这种动态工厂类的最佳实践是什么,但我最终做的(因为所有产品都在同一个包中)是在我的工厂类中创建一个常量来定义我的产品包装:

private const PRODUCT_PACKAGE:String = "com.example.products."; // note the trailing period

因此,您的客户端代码不需要知道(也不定义)产品包。使用getDefinitionByName()时,只需将此常量添加到产品类名称中。