1

Вместо использования жестко закодированного оператора switch, в котором вы передаете ему имя строки класса, а затем создает экземпляр соответствующего класса, я хотел бы передать фактическое имя класс к моему заводскому методу и динамически создать экземпляр этого класса. Я думал, что это будет тривиально, и я удивлен, что он не работает. Должно быть, я что-то довольно основной хватает:AS3 - метод параметризованной фабрики с использованием имени фактического класса

Пример кода:

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?

+0

Ненавижу, когда это происходит - пример, который я опубликовал выше, должен был быть абстракцией моей реальной ситуации в реальном мире. Когда я НАСТОЯТЕЛЬНО проверил мой пример, он работает как первоначально опубликованный, никаких ошибок ссылки. Кровавый ад. Итак, теперь я остаюсь с попыткой выяснить разницу между моим фактическим кодом и этим рабочим примером. Одно из очевидных различий в том, что элемент библиотеки в моей реальной FLA цветовой код GREEN. Я понятия не имею, насколько это значимо - что означает значок элемента с зеленым цветом? –

+0

Никогда не видел символика зеленой кодировки библиотеки до ... удачи! –

+0

Хорошо, зеленый код цвета означает, что связанный класс расширяет Sprite, а не MovieClip. К сожалению, это не проблема в моем конкретном случае. –

ответ

1

getDefinitionByName() и ApplicationDomain.currentDomain.hasDefinition() требуют полных квалифицированных имен классов. Пример кода в исходном сообщении работает, когда Product1Class и Product2Class находятся в пакете по умолчанию. Однако, если вы перемещаете классы продукта в другой пакет, вы должны убедиться, что вы поставляете полное имя класса в getDefinitionByName().

Итак, если мы разместим классы продуктов в com.example.продукты, то вызов становится:

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

Я не совсем уверен, что лучшая практика с такого рода динамического класса фабрики, но то, что я в конечном итоге делает (так как все продукты были в одном пакете) было чтобы создать константу в пределах моей фабрики класса, который определяет пакет для моих продуктов:

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

Так что путь ваш код клиента не нужно знать (и не определить) пакет продукта. Вы просто добавляете эту константу к имени своего продукта при использовании getDefinitionByName().

1

Если у вас есть время выполнения загружается библиотека затем и класса Арканзас e не скомпилирован в основной swf, поэтому при попытке создать их вы получите ошибку задания runtime.

Чтобы обойти это, вы можете объявить «фиктивные» vars классов, которые вы хотите скомпилировать, или если вы используете компилятор flex, есть варианты включения классов, которые вам не хватает.

например. объявить эти где-нибудь в вашем проекте

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

Его расстраивает проблема, если ваши классы продлить мувиклип, который представляет собой динамический класс, который вы могли бы получить доступ к свойствам и т.д., делая что-то вроде этого:

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

Насколько я понимаю, как работает IDE, это не загружаемая библиотека во время выполнения, а должна быть скомпилирована в мой основной SWF (в этом примере я не загружаю внешние SWF-файлы). Меня смущает то, что обычно вы можете получить доступ к любому элементу библиотеки по имени класса, пока вы настраиваете связь в свойствах этого элемента библиотеки. Например, если я экспортирую клип под названием «MCMovie» для ActionScript из панели ссылок, мой основной класс документа может создать его таким образом: var myClip: MCMovie = new MCMovie(); Это в основном то, что я пытаюсь сделать здесь. –

+1

Так Product1Class и Product2Class экспортируются для actionscript? Когда вы связываете символы, вы говорите, что они имеют базовый класс ProductBaseClass (Not MovieClip) правильно? В противном случае ProductBaseClass не будет скомпилирован. Также используйте «var product: ProductBaseClass = new productReference() как ProductBaseClass;» –

+0

Удивительно, что частный var p1: Product1Class или даже var p1: Product1Class = new Product1Class(); все еще не решает проблему. Теперь мне интересно, есть ли что-то еще в игре ... –

1

Крис абсолютно прав, ReferenceError на самом деле бросается во время вызова getDefinitionByName, что означает, что метод отражения не может найти Product1Class или Product2Class в вашем домене приложения. Вы всегда можете проверить, если это определение можно, проверив домен приложения непосредственно, как:

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

Являются ли эти библиотечные активы загружены в во время выполнения? Если это так, вы можете либо убедиться, что библиотека swf загружена в текущий домен приложения, добавив правильно настроенный LoaderContext к вашему загрузчику, или вы можете заменить вызов на getDefinitionByName с помощью метода getDefinition домена приложения swf.

+0

Активы библиотеки встроены в основной (только) SWF-файл, скомпилированный через Flash IDE. Таким образом, нет Loader, и единственным файлом LoaderContext является основной домен приложения. Мне определенно нравится ваш подход к тестированию hasDefinition, а не try..catch. Я буду реализовывать это изменение в моем коде, но это не решает проблему ReferenceError. –