Manual injection into custom class with swiftSuspenders/robotlegs - actionscript-3

in my context:
var parserManager:ParserManager = injector.instantiate(ParserManager);
parserManager.injector = injector;
injector.mapValue(ParserManager, parserManager);
in my parserManager(doesn't extend any other class) class:
public var injector:IInjector;
the parserManager is injected in some models.
Is there a better way of doing it? this is so dirty..

injector.mapSingleton(ParserManager);
var parserManager:Parser = injector.getInstance(ParserManager);
in ParserManager:
[Inject]
public var injector:IInjector
I am a little suspect of injecting the injector into a class with Manager in its name, but that is about the cleanest way I can think of to get it done.
You should keep in mind that after the manager has been mapped, if you don't need it immediately then it will be injected with the injector when it is first created (by being injected in another class that uses it). Robotlegs creates instances lazily.

Related

AS3 Super Class Issue

I have a problem and I'm not too sure the best way to resolve it.
Scenario:
I have a Super Class called 'food' and I have 20 different foods and extends 'food' like Pizza, Curry, Fish and Chip etc.
When I remove a 'food' I keep a record of it so I can reuse (for performance purposes). Can I make a new Pizza class that uses an old 'food'?
E.g.
public class Pizza extends food
{
public function Pizza()
{
super = FOOD.returnUsedFoodClass();
}
}
Is this possible or would I need to save the extending Class as well?
Hope this all make sense.
EDIT:
When I say remove I mean I no longer need it - so I would normally remove all references to it. But instead, I have placed all 'food' classes that I no longer need in a static vector so I can reuse them later.
You misunderstand the basic OOP principles here.
First: a constructor runs only once and only when the object is created so any attempt to stop the creation of the object or replace the object from within its constructor is illogical and cannot succeed since the object at that moment is already created.
Second: Classic misunderstanding of the super keyword. No super doesn't point to any other instance of any other object, super in constructor points to the super class implementation of the constructor. Trying to assign an object to super cannot work and is also illogical. I'm guessing you meant to use 'this' which would also not work anyway.
What you are trying to achieve cannot be done that way and this in any OOP language. There's no way to run a constructor (meaning creating the object) and make this object point to something else within its own constructor. What you are looking for is a classic object pooling system via static methods like this:
var pizza:Pizza = Food.getFood("pizza") as Pizza;
Where the static method checks if any Pizza instance (from the pool) is available and if it is it returns it and if it's not it creates a new one and returns it.
Pooling can be implemented loosely or explicitly, I prefer the more solid and flexible explicit version. Here's an example:
Food class pooling additions:
static private var recycledInstances:Vector.<Food> = new Vector.<Food>();
//hold our reclycled instances
public function recycle():void
{
var index:int = recycledInstances.indexOf(this);
if(index >= 0)
{
return;
}
recycledInstances.push(this);
}
//explicitly add this instance to recycle
private function reset():void
{
}
//to run in constructor and when the instance is retreived from recycle
//this method purpose is to reset all values to default.
Now when an instance is no longer used you call the instance recycle() method to place it in recycle. Then when you need a new instance you do:
var food:Food = Food.getFood();
And this is implemented that way in Food class:
static public function getFood():Food
{
if(recycledInstances.length)
{
var totalInstances:uint = recycledInstances.length;
var instance:Food = recycledInstances[totalInstances - 1];
instance.reset();
recycledInstances.length -= 1;//faster than splice
return instance;
}
return new Food();
}
You can extend this easily to descendant of food class by adding a type member variable to Food for example and check the type of recycled instances before returning them.

Can I still create Global variables in AS3

Following the answer here, I have created a file called MyGlobals.as and placed some global variables and functions so that I can access it from anywhere within my project just like AS3 buil-in functions such as trace() method.
This is MyGlobals.as which is located in the src folder (top level folder)
package {
public var MessageQueue:Array = new Array();
public var main:Main;
public var BOOKING_STATUS_DATA:Object;
public function postMessage(msg:Object):void {
MessageQueue.push(msg);
}
public function processMessage():void {
var msg:Object = MessageQueue.pop();
if (msg) {
switch (msg.type) {
}
}
}
Looks like my IDE (FD4) is also recognizing all these functions and variables and also highlighting the varibles and functions just like any other built-in global functions. However, I am getting compilation errors "Accessing possibly undefined variable xxx". The code is as simple as trace(MessageQueue) inside my Main (or another classe).
I am wondering if there was any change Adboe has done recently that it can't be done now or am I missing something? I am not sure if I need to give any special instructions to FD to include this MyGlobals.as?
I am using FD4, Flex SKD 3.1, FP12.0
I am aware of the best practices which suggests to avoid using this type of method for creating global variables but I really need it for my project for my comfort which I feel best way (right now) when compared to take any other path which involves daunting task of code refactoring. I just want do something which can be done in AS3 which I guess is not a hack.
I've done some playing around; it looks like you can only define one (1) property or method at package level per .as file. It must be the same name (case-sensitive) as the .as file it is contained in.
So no, nothing has changed since the older Flash Versions.
In your case that would mean you need five separate ActionScript files along the lines of:
MessageQueue.as:
package
{
public var MessageQueue:Array;
}
main.as:
package
{
public var main:Main;
}
...etc. As you can see this is very cumbersome, another downside to the many others when using this approach. I suggest using the singleton pattern in this scenario instead.
package{
public class Singleton{
private static var _instance:Singleton=null;
private var _score:Number=0;
public function Singleton(e:SingletonEnforcer){
trace(‘new instance of singleton created’);
}
public static function getInstance():Singleton{
if(_instance==null){
_instance=new Singleton(new SingletonEnforcer());
}
return _instance;
}
public function get score():Number{
return _score;
}
public function set score(newScore:Number):void{
_score=newScore;
}
}
}
then iin your any as3 class if you import the singleton class
import Singleton
thn where u need to update the global var_score
use for example
var s:Singleton=Singleton.getInstance();
s.score=50;
trace(s.score);
same thing to display the 50 from another class
var wawa:Singleton=Singleton.getInstance();
trace(wawa.score)

How to choose which child class to instantiate dynamically

My current project is in as3, but this is something I am curious about for other languages as well.
I'm attempting to use a factory object to create the appropriate object dynamically. My LevelFactory has a static method that returns a new instance of the level number provided to the method. In the code calling that method, I am able to dynamically create the buttons to call the levels like so:
for (var i:int = 1; i < 4; i++) {
var tempbutton:Sprite = createButton("Level " + i, 25, 25 +(60 * i), start(i));
_buttons.push(button);
}
This code just creates a simple button with the given arguments (ButtonText, x, y, function). It's working fine. The buttons are created, and clicking on one of them calls this method with the appropriate argument
private function start(level:int):Function {
return function(e:MouseEvent):void {
disableButtons();
newLevel = LevelFactory.createLevel(level);
addChild(newLevel);
}
}
This is all working fine; I'm just providing it for background context. The question I have is this: Is it possible to dynamically choose the type of object that my static function returns? Currently, I have am doing it as follows
public static function createLevel(level:int):Level {
var result:Level;
switch(level) {
case 1: result = new Level1(); break;
case 2: result = new Level2(); break;
//etc
}
return result;
}
I should note that all of these Level1, Level2, etc. classes extend my base level class. (Yay polymorphism!) What I would like to do is be able to do something along the lines of
public static function createLevel(level:int):Level {
var result:Level;
var levelType:String = "Level" + level;
return new levelType();
}
Obviously it's not going to work with a string like that, but is there any way to accomplish this in as3? What about other languages, such as Java or Python? Can you dynamically choose what type of child class to instantiate?
Update:
import Levels.*;
import flash.events.*;
import flash.utils.*;
public class LevelFactory
{
public static function createLevel(level:int):Level {
var ref:Class = getDefinitionByName('Levels.' + 'Level' + level) as Class;
var result:Level = new ref();
return result;
}
}
Update/Edit: getDefinitionByName seems to be what I'm looking for, but it has a problem. It seems that the compiler will strip unused imports, which means that unless I declare each subclass in the code ahead of time, this method will get a reference error. How can I get around the need to declare each class separately (which defeats the purpose of dynamic instantiation)?
Yes, you sure can, and it's very similar to the string thing that you've provided. The only thing that you are missing is the getDefinitionByName method: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/package.html#getDefinitionByName()
You can generate whatever class name you want, and what this method does is that it searches for that class in it's namespace, and if it finds it - it returns it as a class:
var ClassReference:Class = getDefinitionByName("flash.display.Sprite") as Class;
var instance:Object = new ClassReference();
This piece of code will instantiate a Sprite. This way you can instantiate your classes without all those switches and cases, especially when you have to make a hundred levels :)
Hope that helps! Cheers!
Edit:
In your case, the code should be:
var ref:Class = getDefinitionByName('com.path.Level' + index) as Class;
var level:Level = new ref(); // it will actually be Level1 Class
Since Andrey didn't quite finish helping me out, I am writing up a more complete answer to the question after much research.
getDefinitionByName definitely has the use I am looking for. However, unlike its use in Java, you HAVE to have a hard reference to the class you want instantiated somewhere in your code. Merely imported the class is not enough; the reason for this is that the compiler will strip the reference from any unused import to save space. So if you import the package of classes you want to choose dynamically but don't have a hard reference to them, the compiler will de-reference them. This will lead to a run-time error when the program cannot find the appropriate reference to your class.
Note that you don't actually have to do anything with the reference. You just have to declare a reference so that it can be found at run-time. So the following code will work to eliminate the switch-case statement and allow me to dynamically declare which class I am using at run-time.
{
import Levels.*;
import flash.events.*;
import flash.utils.*;
/**
*
* Returns the requested level using the createLevel class
* ...
* #author Joshua Zollinger
*/
public class LevelFactory
{
Level1, Level2, Level3, Level4, Level5, Level6, Level7;
public static function createLevel(level:int):Level {
var ref:Class = getDefinitionByName('Levels.Level' + level) as Class;
var result:Level = new ref(); // it will actually be the correct class
return result;
}}}
The obvious downside to this is that you still have to have a hard-coded reference to every class that can be instantiated like this. In this case, if I try to create a Level8 instance, it will through a run-time error because Level8 is not referenced. So every time I create a new level, I still have to go add a reference to it; I can't just use the reference dynamically.
There are supposedly ways around this that I have not tested yet, such as putting the code for the classes in a separate SWF and importing the SWF at run-time or using outside libraries that will have different functionality. If anyone has a solid way to get a truly dynamic reference that doesn't require a hard coded reference anywhere, I would love to hear about it.
Of course, it's still a lot cleaner this way; I don't have a extensive switch case statement to pack all the levels. And it's easier and faster to add a reference to the list than creating a new case in a switch. Plus it is closer to dynamic programming, which is usually a good thing.

Instantiate an Fxg on runtime using getDefinitionByName in Flex

i have a little problem with getDefinitionByName.
My purpose is to instantiate an FXG object(Number10.fxg) in a document mxml on runtime.
The name of the Class is in a string variable that is used by getDefinitionByName
to return the name of the class to insantiate. The code doesn't work even if doesn't send an error message. The code is as follows:
import assets.Number10;
import flash.utils.getDefinitionByName;
import mx.core.IVisualElement;
private function onClick(event:MouseEvent):void
{
var value:String = "Number10";
var ClassDefinition:Class = getDefinitionByName(value) as Class;
var ten:IVisualElement = new ClassDefinition() as IVisualElement;
this.contentGroup.addElement(ten);
}
I tried also with... var ten:IVisualElement = new ClassDefinition();
but nothing. It Doesn't work!
Please, Help me!
First of all, i refer to the adobe documentation pages that covering the topic so telegraphic. Here it is:
Option includes class [...]
Description Links one or more classes to the resulting application SWF file, whether or not those classes are required at compile time.
To link an entire SWC file rather than individual classes, use the include-libraries option.
Ok.In Flash Builder i go to the Additional compiler arguments where there is just this option
-locale en_US
So i add my option under this
-includes class = assets.Number10
or
-includes class assets.Number10
or
-includes class Number10
When the application runs i get the Error #2032.
I think that the option declaretion is wrong. I do not have a good reference for using option.
So...Help me!
How can i declare the Number10 class or the assets package with the other fxg object using the includes class option?
Ok! I find the solution...
Is to put a reference to Number10 class somewhere in the code, for instance:
import assets.Number10;
import flash.utils.getDefinitionByName;
import spark.core.SpriteVisualElement;
//case1
var myNumber:Number10;
//or
//case2
Number10;
private function onClick(event:MouseEvent):void
{
var value:String = "assets.Number10";
var ClassDefinition:Class = getDefinitionByName(value) as Class;
var ten:SpriteVisualElement = new ClassDefinition() as SpriteVisualElement;
this.contentGroup.addElement(ten);
}
and the code works :-)
This is a problem that comes from the way that Flex compiles its code. Flex compiles its code so that if a class is not used, it will keep this class off the final compiled program.
But the problems are not over yet! If i have hundreds of Fxg objects that could be instantiate, declaring all classes is little difficult and tedious.
So, how i can delclare in one time all classes of a package?
You can add classes to SWCs and SWFs using the include and includeClasses compiler options. Using these, you don't have to reference the classes in the code. Consult the documentation for proper usage.
Be sure to use the fully qualifed class name.
Also, the approach of casting your FXG class as an IVisualElement is new to me. I thought you had to use real classes in casting and the sort. Try using a SpriteVisualElement.
private function onClick(event:MouseEvent):void
{
var value:String = "assets.Number10";
var ClassDefinition:Class = getDefinitionByName(value) as Class;
var ten:IVisualElement = new ClassDefinition() as SpriteVisualElement.;
this.contentGroup.addElement(ten);
}

Overriding public method in dynamically loaded class with AS3 and getDefinitionByName()

I have two SWFs: main.swf and external.swf. main.swf needs to access some methods in external.swf, so it loads external.swf into itself and uses getDefinitionByName("package.Class") to access the class and one of its methods:
var ExternalClass = getDefinitionByName("package.Class") as Class;
var ClassInstance = new ExternalClass();
var NeededFunction:Function = ClassInstance["NeededFunction"] as Function;
var response:String = NeededFunction(param);
Now, I need to extend the functionality of NeededFunction (which is a public method)... I know it's possible to override public methods, but how would I go about this with a dynamically loaded class?
I was thinking I could do something like this, but it doesn't work:
var ClassInstance["NeededFunction"] = function(param1:uint):String {
var newString = "Your number is: "+param1.toString(); //New functionality
return newString;
}
Another way to deal with this could be to have the classes in a package that's accessible by both SWFs. Just add the classes' root folder to your Actionscript path .
Instead of getting a class by using getDefinitionByName , you simply import it. As for overriding , you can create a Class that overrides one of the classes , or you can create an Interface.
import com.yourlocation.ExternalClass;
var external:ExternalClass = new ExternalClass();
Using FlashDevelop this is pretty simple to fix.
Right click your included swc from the Project list.
Choose options then "include library (complete library)".
..you can now use getDefinitionByName to get a unreferenced class from your swc file.