【问题标题】:AS3 - Parametrized Factory method using actual class nameAS3 - 使用实际类名的参数化工厂方法
【发布时间】:2011-06-04 02:28:13
【问题描述】:

我不想使用硬编码的 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?");
    }
 }

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

为什么会出现 ReferenceError?

【问题讨论】:

  • 我讨厌这种情况发生 - 我在上面发布的示例旨在抽象出我的实际现实情况。当我实际测试我的示例时,它按最初发布的方式工作,没有参考错误。该死的地狱。所以现在我要弄清楚我的实际代码和这个工作示例之间的区别。一个明显的区别是,我现实世界的 FLA 中的图书馆项目是用颜色编码的绿色。我不知道它是否重要 - 绿色编码的图书馆项目图标是什么意思?
  • 以前从未见过绿色编码的库符号...祝你好运!
  • 好的,绿色代码只是意味着链接的类扩展了 Sprite 而不是 MovieClip。不幸的是,在我的特殊情况下,这不是解决方法。
  • 当产品类不在默认包中时,上面的示例不起作用。这是我不明白的部分。如果 Product1Class.as 文件与 FLA 和文档类位于同一目录中(无论 Factory 类在哪里),则它可以按预期工作。当您将 Product1Class 放入其自己的包(例如 com.test.products)中时,您会收到参考错误。那是怎么回事?

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


【解决方案1】:

如果您有一个运行时加载的库,那么类不会编译到主 swf 中,因此当您尝试创建它们时会遇到运行时引用错误。

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

例如在项目的任何地方声明这些

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

【讨论】:

  • 据我了解 IDE 的工作原理,这不是运行时加载的库,而是应该编译到我的主 SWF 中(在此示例中我没有加载任何外部 SWF)。让我感到困惑的是,通常,只要您在该库项目的属性中设置链接,您就可以按类名访问任何库项目。例如,如果我从链接面板为 Actionscript 导出一个名为“MCMovie”的剪辑,我的主文档类可以这样实例化它: var myClip:MCMovie = new MCMovie();这基本上就是我在这里想要做的。
  • 那么 Product1Class 和 Product2Class 是为 actionscript 导出的吗?当您链接符号时,您说它们属于基类 ProductBaseClass(不是 MovieClip),对吗?否则 ProductBaseClass 将不会被编译。也使用 "var product:ProductBaseClass = new productReference() as ProductBaseClass;"
  • 令人惊讶的是,私有 var p1:Product1Class 甚至 var p1:Product1Class = new Product1Class();仍然没有解决问题。现在我想知道是否还有其他事情在起作用......
  • 是的,它们是为 ActionScript 导出的。我没有在 Linkage 部分使用 Base 类(默认为 MovieClip)。我正在使用 Class 链接到我的特定 Product1Class。这是因为 Product1Class 和 Product2Class 封装了彼此不同的功能并覆盖了基类抽象方法。
【解决方案2】:

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

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

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

【讨论】:

  • 库资源嵌入在主(仅)SWF 中,通过 Flash IDE 编译。所以没有Loader,唯一的LoaderContext就是主应用域。我绝对喜欢你测试 hasDefinition 的方法,而不是 try..catch。我将对我的代码实施该更改,但它不能解决 ReferenceError。
【解决方案3】:

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() 时,您只需将此常量添加到您的产品类名称中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-27
    • 1970-01-01
    • 2019-12-22
    相关资源
    最近更新 更多