Here are some benefits I think will immediately appear :
1. Life-cycle of the components will be much easier to understand and eventually tweak upon needs. By separating concerns in behavior classes, anyone will be able to understand the logic behind it and extend that class rather than altering the life-cycle in some undesired way.
2. The new Apache SDK will maintain compatibility with existing SDKs, allowing existing developers to use the SDK the way they learned it, gradually migrating to this new way. All those existing tutorials will be still valid for the new SDK, until the community will create new ones to document how to make use of the behavior classes.
3. All UIComponents extenders will become lightweight : I’m just thinking that now, a spark component is fast, but could be even faster by “dismounting” unwanted behavior from ‘hostComponent’ and mounting it to the skin.
4. Directly from the above, we will benefit of a smaller memory foot print and a lightweight job for SDK’s managers. I’m thinking, being able to control what the SDK’s managers are handling, just by removing unwanted behavior classes from our components.
5. Having specialized behavior classes, we will be able to reuse code much efficiently, without the danger of having a premature optimization case.
6. Will provide a very powerful way of including other frameworks directly into SDK (thinking about beloved Spring or RobotLegs) just by overriding behavior classes to have injections.
7. Will provide an easier way to write inspector classes and/or custom automation (I will not get into details).
8. Flex will become even more flexible, allowing advanced developers to do magic things just by adding or altering behavior classes.
I’ve been asked for an example, so here it is. Read this first, but look to it as an abstraction.
package org.apache.flex.five.corebehaviors
{
import flash.display.DisplayObject;
import flash.events.FocusEvent;
import org.apache.flex.five.interfaces.IBehavior;
import org.apache.flex.five.interfaces.IUIComponent;
public final class FocusListener implements IBehavior
{
private var _target : IUIComponent;
public function FocusListener(target : IUIComponent)
{
_target = target;
_target.addEventListener(FocusEvent.FOCUS_IN, focusInHandler);
_target.addEventListener(FocusEvent.FOCUS_OUT, focusOutHandler);
}
protected var _name : String = "org.apache.flex.five.interfaces.FocusListener";
public function get name():String
{
return _name;
}
public function destroy():void
{
_target.removeEventListener(FocusEvent.FOCUS_IN, focusInHandler);
_target.removeEventListener(FocusEvent.FOCUS_OUT, focusOutHandler);
}
protected function isOurFocus(target:DisplayObject):Boolean
{
return _target == this;
}
private var _focusManager:IFocusManager;
public function get focusManager():IFocusManager
{
if (_focusManager)
return _focusManager;
var o:DisplayObject = _target.parent;
while (o)
{
if (o is IFocusManagerContainer)
return IFocusManagerContainer(o).focusManager;
o = o.parent;
}
return null;
}
protected function focusInHandler(event:FocusEvent):void
{
if (isOurFocus(DisplayObject(event.target)))
{
var fm:IFocusManager = focusManager;
if (fm && fm.showFocusIndicator)
drawFocus(true);
ContainerGlobals.checkFocus(event.relatedObject, this);
}
}
protected function focusOutHandler(event:FocusEvent):void
{
if (isOurFocus(DisplayObject(event.target)))
drawFocus(false);
}
public function drawFocus(isFocused:Boolean):void
{
//to be implemented
}
}
}
Where interfaces are :
package org.apache.flex.five.interfaces
{
public interface IBehavior
{
function get name():String;
function destroy():void;
}
}
package org.apache.flex.five.interfaces
{
import flash.events.IEventDispatcher;
public interface IUIComponent extends IEventDispatcher
{
}
}
And UIComponent :
package org.apache.flex.five.core
{
import flash.display.Sprite;
import flash.utils.Dictionary;
import org.apache.flex.five.corebehaviors.FocusListener;
import org.apache.flex.five.interfaces.IBehavior;
import org.apache.flex.five.interfaces.IUIComponent;
public class UIComponent extends Sprite implements IUIComponent
{
private var _behaviours : Dictionary = new Dictionary();
public function UIComponent()
{
super();
}
/**
**/
protected var _isFocusable : Boolean;
public function get isFocusable():Boolean
{
return _isFocusable;
}
public function set isFocusable(value:Boolean):void
{
_isFocusable = value;
if (value)
{
var focusListener : IBehavior = new FocusListener(this);
addBehavior(focusListener);
}
else
{
removeBehavior("org.apache.flex.five.interfaces.FocusListener");
}
}
public function addBehavior( action : IBehavior ) : void
{
_behaviours[action.name] = action;
}
public function removeBehavior( named : String) : void
{
var behavior : IBehavior = _behaviours[name];
behavior.destroy();
_behaviours[name] = null;
}
}
}
As you can see, it’s a very draft example but explains what I mean. If a component will not use certain behaviors (in our case focus), we will not consume memory with unused code, we will not listen for focus events. Think in terms of resizing, accessibility, resource bundles…
As you probably know, a behavior class is somehow a simple controller for a target which does one only thing, controlling the target with a single specific goal or feature. Main idea behind this design pattern is to add functionality by assigning a behavior to an object by composition instead of extending it to get that functionality (inheritance).
I think the next generation of UIComponent should make use of behavior design pattern due to it’s clean and reusable code, a lightweight UIComponent which will allow developers eventually to use event bubbleing without adding a heavy class to the display list.
I am convinced that life cycle of UIComponent will change in a new and flexible way. Just imagine that we could differentiate between interests of the subclasses, thus reducing the load on managers.
Let me know if you don’t agree with this point of view, if you have experiences with behavior design patterns and think of possible drawbacks : I’m trying to figure out if I should suggest this approach to Apache Flex mailing list.