CARVIEW |
Navigation Menu
-
Notifications
You must be signed in to change notification settings - Fork 2
4. Create wires
The wires are classes that hold the logic of the application.
A wire and is the glue between other framework elements such as models, views and other wires. Most of the time, a wire will have a specific role and responsibility in your application. A wire is a central point that can creates other wires, commands, models and views.
You can create as many wires as you need, they are the free elements in the framework.
A wire is also the framework element that has an easy access to everything else, such as other wires, models, views, commands, framework instance, stage, and so on. Wires can be flexible or rigid depending of the needs of your application.
The name of a wire is only necessary to register it to the framework if injection is not used.
A wire is also a good place (as mediators) to control the flow of your application. By listening to events and commands, you can monitor what is happening in your application and intercept commands to stop their action if necessary. The difference between a wire and a mediator is that a mediator is responsible for a single view (one to one relation), while a wire can be responsible for anything.
Your wire class must extends Wire
and implements IWire
.
Two methods can be overridden for conveniency, the initialize method will be called once a wire has been added to the framework and the dispose method will be called once a wire has been removed from the framework. The initialize method can be used as a starting point to create other framework elements, listen to events and commands while the dispose method is used to destroy what has been created or what it is responsible for.
package {
import com.soma.core.wire.Wire;
import com.soma.core.interfaces.IWire;
public class WireExample extends Wire implements IWire {
public static const NAME:String = "Wire example name";
public function WireExample() {
super(NAME);
}
override public function initialize():void {
// called when the wire has been registered to the framework
}
override public function dispose():void {
// called when the wire has been removed from the framework
}
}
}
There are two ways to register a wire to the framework and this can be done in four places:
- in the framework instance
- in another wire instance
- in a mediator instance
- in a command instance
In either place, a wire can be registered this way:
addWire(WireExample.NAME, new WireExample());
The wire instances registered to the framework can easily be retrieved in the same three places.
var wire:IWire = getWire(WireExample.NAME);
var wireExample:WireExample = getWire(WireExample.NAME) as WireExample;
A wire class that is not used anymore can be removed in the same four places. When a wire gets removed, the framework will automatically call its dispose method and set to null in order to be garbage collected.
removeWire(WireExample.NAME);
if (hasWire(WireExample.NAME)) {
// do something
}
It is a good practice to create getter shortcuts, for example in another wire. Here are some examples:
private function get wireExample():WireExample {
return WireExample (getWire(WireExample.NAME));
}
private function get wireExampleProperty():XML {
return WireExample(getWire(WireExample.NAME)).myProperty as XML;
}
They can now be used directly from another place:
override protected function initialize():void {
trace(wireExample.doSomething());
}
Injection makes it even easier to register and retrieve a wire. A wire that will be injected will have the same form beside the name that is not needed, unless you wish to both use injection and register it to the framework registry.
package {
import com.soma.core.wire.Wire;
import com.soma.core.interfaces.IWire;
public class WireExample extends Wire implements IWire {
override public function initialize():void {
// called when the wire has been registered to the framework
}
override public function dispose():void {
// called when the wire has been removed from the framework
}
}
}
They are many ways to register a wire to the framework using injection depending of the behavior wanted when it gets injected.
If only one instance of a wire class must be created, the wire can be registered using the injector.mapSingleton()
method. The name Singleton doesn’t mean that it is a real Singleton. It means that only one instance will be created when needed, making a good of lazy instantiation, and that the same instance will be injected every time it is asked.
injector.mapSingleton(WireExample);
This line means: every time I ask for a WireExample to be injected, create a new instance of the WireExample if it is the first time I ask. Otherwise, inject the instance that has been already created.
An instance can be created before being injected, if needed, using the injector.getInstance()
method.
var wire:WireExample = injector.getInstance(WireExample) as WireExample;
If a wire requires to be a new instance every time it gets injected, the method injector.map()
can be used.
injector.map(WireExample, WireExample);
This line means: every time I ask for a WireExample to be injected, create a new instance of the WireExample class.
A wire can also be instantiated and registered to the injector. Every time, the wire class must be injected, this precise instance will be used for the injection.
var wire:WireExample = new WireExample();
injector.mapToInstance(WireExample, wire);
This line means: every time I ask for a WireExampleto be injected, use the wire instance that has been registered.
A wire class or instance can be unregistered (unmapped) from the injector using the injector.removeMapping()
method.
injector.removeMapping(WireExample);
To inject a wire instance in another class, the injector will need to find a [Inject]
metadata tag in the injectee class.
To perform an injection, the injectee class must be created by the injector, or manually with the injector.injectInto()
method.
Here is a simple example of a wire that get injected in another wire.
// mapping rule
injector.mapSingleton(WireExample);
// create another wire instance to inject the wire example into
injector.getInstance(AnotherWire);
// or
var wire:AnotherWire = new AnotherWire();
injector.injectInto(wire);
package {
import com.soma.core.wire.Wire;
import com.soma.core.interfaces.IWire;
public class AnotherWire extends Wire implements IWire {
[Inject]
public var wire:WireExample;
override public function initialize():void {
// called when the wire has been registered to the framework
trace("wire injected:", wire);
}
override public function dispose():void {
// called when the wire has been removed from the framework
}
}
}
A wire can access to all the framework elements and other application elements. Here are some examples:
[Inject]
public var myWire:WireExample; // retrieve a wire using injection
[Inject]
public var myModel:WireModel; // retrieve a model using injection
override public function initialize():void {
// access to the application instance (see Framework Instance section for more examples)
var myApplication:ISoma = instance;
// access to the stage
trace("Stage: ", stage);
// access to the injector
var injector:ISomaInjector = injector;
// access to wires method
addWire(OtherWire.NAME, new OtherWire());
hasWire(OtherWire.NAME);
var wire:OtherWire = getWire(OtherWire.NAME) as OtherWire;
removeWire(OtherWire.NAME);
// access to models
addModel(ModelExample.NAME, new ModelExample());
hasModel(ModelExample.NAME);
var model:ModelExample = getModel(ModelExample.NAME) as ModelExample;
removeModel(ModelExample.NAME);
// access to views
addView(NAME_VIEW, new MySprite());
hasView(NAME_VIEW);
var mySprite:MySprite = getView(NAME_VIEW) as NAME_VIEW;
removeView(NAME_VIEW);
// access to mediators
mediators.mapView(MySprite);
mediators.hasMediators(mySprite);
mediators.isMapped(MySprite);
mediators.removeMapping(MySprite);
// access to commands
addCommand(MyEvent.DO_SOMETHING, MyCommand);
hasCommand(MyEvent.DO_SOMETHING);
removeCommand(MyEvent.DO_SOMETHING);
getCommands();
// listen to commands or events
addEventListener(MyEvent.DO_SOMETHING, handler);
removeEventListener(MyEvent.DO_SOMETHING, handler);
}
A powerful Soma feature is not only its event and command system, but the capability to monitor them and control the flow of the application.
When a command is dispatched from either a view or another framework element, or an event is dispatched from a framework elements. A wire (or mediator) is able to monitor this event by just listening to it.
Let’s take a simple example. A sprite button that has a label “quit” will dispatch a ApplicationEvent.QUIT
event.
private function quitHandler(event:MouseEvent):void {
dispatchEvent(new ApplicationEvent(ApplicationEvent.QUIT));
}
Because this event has been registered to the framework and became a command, the application can dispatch command from the views and still be decoupled from the application as are they simple flash built-in events.
addCommand(ApplicationEvent.QUIT, ApplicationCommand);
The ApplicationCommand
will take care of the event. For example, quit the desktop application if the application was built with Adobe AIR. But in some cases, for some reasons, we don’t want the application to quit, for example if we want to ask the user if he really wants to quit.
Another framework element such as a wire or a mediator can monitor the commands and decide whether to stop the execution.
package {
import com.soma.core.wire.Wire;
import com.soma.core.interfaces.IWire;
public class QuitPanelWire extends Wire implements IWire {
override public function initialize():void {
// called when the wire has been registered to the framework
addEventListener(ApplicationEvent.QUIT, quitHandler);
}
private function quitHandler(event:ApplicationEvent):void {
if (shouldNotQuitForSomeReasons) {
event.preventDefault(); // stop the execution of the command
quitPanel.show(); // show panel to ask the user if we wants to quit
}
}
override public function dispose():void {
// called when the wire has been removed from the framework
removeEventListener(ApplicationEvent.QUIT, quitHandler);
}
}
}
It is that simple to monitor and control the flow of your application, simple flash built-in event methods such as addEventListener
, removeEventListener
, and preventDefault()
.
Note: the custom event ApplicationEvent
will have to be set with a bubble property true to be considered as a command, and a cancelable property set to true to stop its execution.
public function ApplicationEvent(type:String, bubbles:Boolean = true, cancelable:Boolean = true) {
super(type, bubbles, cancelable);
}