Dependency Injection for Flash


Dependency injection is a software design pattern that allows the removal of hard-coded dependencies and makes it possible to change them, whether at run-time or compile-time.

What does it give to you?
– The usage of Hollywood principle to provide objects with what they depend on. “Don’t call us, we’ll call you!”
– You look at your objects as services and their clients (if you want to get more in depth with it, I highly recommend to read that brilliant book “Dependency Injection“)
– You can easily mock dependecies while testing of a concrete component
– Remove the need of objects to know about their dependencies and how to create them
– Forget about Singleton Pattern!!!

Dependency Injection for Flash
SwiftSuspenders is the most popular DI framework for Flash. Also it is a part of a popular Robotlegs framework and other projects.

The idea is to create an injector, map your dependecies and inject them into the target object.
please read the following example code
Main.as:

package {
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
 
	import org.swiftsuspenders.Injector;
 
	public class Main extends Sprite {
		//mark fields for injection
		[Inject]
		public var classA:ClassA;
 
		[Inject]
		public var classB:ClassB;
 
		[Inject]
		public var applicationStage:Stage;
 
		public function Main() {
			addEventListener(Event.ADDED_TO_STAGE, onAdded);
		}
 
		private function onAdded(event:Event):void {
			removeEventListener(Event.ADDED_TO_STAGE, onAdded);
 
			var bg:Sprite = new Sprite();
			addChild(bg);
			//lets create Injector Object and map dependencies
			var injector:Injector = new Injector();
			//map ClassA, the mappint says that injector can create it if someone is needed for ClassA
			injector.map(ClassA);
			//map ClassB as Singleton
			injector.map(ClassB).asSingleton();
			//map class to value
			injector.map(Stage).toValue(stage);
			//map class to type
			injector.map(DisplayObject).toType(Sprite);
			//named class map to value
			injector.map(Sprite,"mainBg").toValue(bg);
			//inject into Main object
			injector.injectInto(this);
		}
 
		//run initInstance method after injection has been completed and all dependecies are created
		[PostConstruct]
		public function initInstance():void {
			trace(applicationStage);// [object Stage]
			trace(classA);// [object ClassA]
			trace(classB);// [object ClassB]
		}
	}
}

ClassA.as:

package {
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.display.Stage;
 
	public class ClassA {
		[Inject]
		public var applicationStage:Stage;
 
		[Inject(name="mainBg")]
		public var background:Sprite;
 
		[Inject]
		public var castedSprite:DisplayObject;
 
		[Inject]
		public var bObject:ClassB;
 
		[Inject(optional=true)]
		public var optionalClip:MovieClip;
 
		public function ClassA() {
			trace(applicationStage);//traces null
			trace(background);//traces null
			trace(castedSprite);//traces null
			trace(bObject);//traces null
			trace(optionalClip);//traces null
		}
 
		[PostConstruct]
		public function initInstance():void {
			//now you can access them here
			trace(applicationStage);// [object Stage]
			trace(background);//[object Sprite]
			trace(castedSprite);//[object Sprite]
			trace(bObject);//[object ClassB]
			trace(optionalClip);//null
		}
	}
}

ClassB.as:

package {
	public class ClassB {
		public function ClassB() {
			trace("ClassB Created");
		}
	}
}

SwiftSuspenders features:

– injection requests configurable using standardized metadata
– can inject into vars, setters, methods and constructors
– injection requests can be optional
– mapping dependencies by class and, optionally, name
– satisfying dependencies using value, class instance, singleton or custom providers
– chaining multiple injectors to create modular dependency-mapping graphs much like inheritance works in OOP
– defining local and shared scope for mappings, akin to public and private members of a class
– defining soft mappings that only get used if no injector higher up in the inheritance chain can satisfy a dependency
– support object live-cycle management (note: The latter part of that management, i.e. the destruction, is not yet implemented, but will be for 2.0 final)

The primary purpose of the dependency injection pattern is to allow selection among multiple implementations of a given dependency interface at run time, or via configuration files, instead of at compile time. Without dependency injection, a consumer component that needs a particular service in order to accomplish a task must create an instance of a class that concretely implements the dependency interface. When using dependency injection, a consumer component specifies the service contract by interface, and the injector object selects an implementation on behalf of the dependent component. Furthermore, dependency injection facilitates the writing of testable code.

Thank you! Happy coding!)

P.S. Circular dependencies should really be avoided as a best practice.

SergeyGonchar
flash-developer
Visit Gonchar Website.

One Response to “Dependency Injection for Flash”

  1. How does this affect performance? Especially on mobile…

Leave a Reply

×
%d bloggers like this: