Flex pattern: Set property name or type at run-time

Scenario: I felt confused/embarrassed when the Starbucks barista asked me “What kind of milk?” when I asked for a “Misto“. Me, standing rolling my eyes, with a few thoughts quickly spinning around/above my head: doesn’t all the milk look same here? Do they also put soy milk in the coffee? Or maybe they have black milk here? I couldn’t figure out what my options would be after 2 seconds. So I probed: “What kind of milk do you offer?:D” She kindly replied: “1%, 2%, skim, etc..”

I guess the barista was expecting some basic knowlege which I obviously didn’t acquire by culture. (Oh yeah she is from the coffee culture and me from the tea culture for a side note.)

Let’s go back to our pattern thread. As developers of components, we want to apply loose coupling philosophy to our component architecture. Sometimes classes need to obtain their values from other objects rather than through locally set values and type selectors.

  1. Sometimes we’d like to have the developer determine certain aspects of our components (with these aspects esp. being states or styles of our components). Flex pattern: If you are creating components that are creator and manager of the data renderers, and your component are altering the renderers states by expecting them to “have” certain states, instead of hard code those state names locally into your data renderers, expose sub component state values as styles of the creator object and let the developer set them at runtime.

    var stateProperty:String = getStyle("stateProperty");//currentState
    var rolloverState:String = getStyle("rolloverValue");
    ...
    renderers[i][stateProperty] = (i == selectedItemIndex)? selectedState:
    (i==hilightedItemIndex)? rolloverState:unselectedValue;

    One thing attempting to do when you write your own custom component is to dictate the states of your descendant components  in the ancestor component (e.g. the creator of item renderers intrudes into the framework of the itemRenderers).  As in the following code, the component developer requires (sort of, since it recovers by using NaN;)) that the renderer implement “selectedStates”. Doesn’t look very elegant.

    //Code in AnimatedRandomWalk.as
    override protected function commitProperties():void
    {
    //……
    /**it’s often the case that a component will have more information its item renderers might be interested in than just the data.  It’s the practice in Flex to define a separate interface to allow define the additional information your component might pass to an item renderer.  Try not to require that your item renderers implement this interface…it’s nice to provide customers with the option to invest less effort but still get a gracefully degrading experience.
    in this case, we think our item renderers might want to render differently based on whether they’re selected or not.  While in controlled situations, you could just explicitly set the ‘currentState’ property of your renderers, If you want to allow developers to swap in different item renderers, that’s not a great idea. It essentially hijacks the view states of the item renderer, and doesn’t allow the developer to add additional states or behavior.  Better to let them manage their own currentState.*/
    if (inst is IRandomWalkRenderer)
    IRandomWalkRenderer(inst).selectedState = (isNaN(selectedIndex)?  NaN:
    (selectedIndex == j)?     1:
    0);
    //……
    }

    With this being said, since our component _is_ interested in the states other than just data of the renderers, how do we let them know when we want them to change states? One thing we can do this more elegantly (or, hmm, “unobtrusively”) is to not to hard code the values of the states into our component since we don’t know what states the developers already have had in his plate and we don’t want to force the developers to implement those states as we require. But what we can do (tactfully;-)), is to expose our options (done by public members and styles in Flex) for these states and have the developers make their decisions of their own at run-time, just as the nice brista lady showed me what options I would have for the milk in my coffee. Of course the developer may completely ignore these options, which would require us to handle the situation gracefully, as mentioned as “degrading experience” by Ely in his RandomWalk component.

    Here is how Ely did it in his FishEye component :

    //snippets of code in FisheyeBase.as
    /**
    * update the state properties of all of the items, based on
    * the current hilighted and/or selected items
    */
    private function updateState():void
    {
    var stateProperty:String = getStyle(“stateProperty”);
    if(stateProperty != null)
    {
    var rolloverState:String = getStyle(“rolloverValue”);
    var selectedState:String = getStyle(“selectedValue”);
    var unselectedValue:String = getStyle(“unselectedValue”);
    if (unselectedValue == null || (isNaN(selectedItemIndex) && isNaN(hilightedItemIndex)))
    unselectedValue = getStyle(“defaultValue”);

    for(var i:int=0;i<renderers.length;i++)
    {
    renderers[i][stateProperty] = (i == selectedItemIndex)? selectedState:
    (i==hilightedItemIndex)? rolloverState:
    unselectedValue;
    }
    }
    }//endof snippets in FisheyeBase.as

    //in the “main” MXML, this is what is supposed for a developer to do:
    <qs:Fisheye xmlns:qs=”qs.controls.*” height=”100%” dataProvider=”{src}”
    hilightScaleSlope=”3″ hilightMinScale=”.2″
    stateProperty=”currentState” rolloverValue=”rollOver” defaultValue=”” selectedValue=”selected”
    horizontalAlign=”left”>
    <qs:itemRenderer>
    <Component>
    <qs:CachedLabel xmlns:f=”flash.filters.*” color=”#FFFFFF”>
    <qs:states>
    <State name=”selected”>
    <SetProperty name=”filters”>
    <value>
    <Array>
    <f:GlowFilter  color=”#888888″/>
    </Array>
    </value>
    </SetProperty>
    <SetStyle name=”color” value=”#E27C0E” />
    </State>
    <State name=”rollOver”>
    <SetProperty name=”filters”>
    <value>
    <Array>
    <f:GlowFilter  color=”#BBBBBB”/>
    </Array>
    </value>
    </SetProperty>
    </State>
    </qs:states>
    </qs:CachedLabel>
    </Component>
    </qs:itemRenderer>
    </qs:Fisheye>
    //endof main snippets

  2. In some other cases, we don’t know what type (of UIComponent) we would use to render certain data items, or in other words, we like the flexibility of being able to leave the decision up to the developer.

Concept: There is normally a two-tier hook to this kind of things. For case #1, first we store a reference to the _name_ of the property, and provide public ways for the developer to set the name of the property. Under the hood, we query the property name at run-time and wire it back to the parts, which have this property as their data member. After the we know the property of interest, we then retrieve and set all the real values. which actually set values for the aforementioned parts data member. For case #2, we store a reference to the _type_, often as an interface, in our class. When the time comes when we need to declare and initialize one of a concrete type, we take the type that the developer sets, or in the case it’s not defined, we can provide our abstract type.  Till now we can see #2 is usually associated with factory method pattern. It sounds strange and stretchy to me if we call #1 as “Factory property pattern” although it is an innovative attempt.

Solution:

For #1, they manifest in the form of styles of UIComponent.  The mx.styles.ISimpleStyleClient has a styleName getter which means “the source of this object’s style values”.  One of the scenarios is  the object that implements this interface inherits all the style values from the referenced UIComponen; Another use case is you can use a String which names a class selector that is defined in a CSS style sheet; A third case is to use CSSStyleDeclaration, such as StyleManager.getStyleDeclaration(“.headerStyle”)...

For #2, they appear in IFactory, ClassFactory which are used for creating item renderers.

//sample code for our customcomponent

private var _itemRenderer:IFactory;

public function CustomComponentConstruct()

{

...

_itemRenderer = new ClassFactory(Image);

...

}//end of sample code

/////////////////////////

//sample code for mx.core.ClassFactory

public var generator:Class

public function ClassFactory(generator:Class = null)
{
super();

this.generator = generator;
}
public function newInstance():*
{
//instantiate new class object. Note that we type "instance" as Object as opposed to Class:
var instance:Object = new generator();
//This is another pattern where we aggregate all children properties to their "owner"
if (properties != null)
{
for (var p:String in properties)
{
instance[p] = properties[p];
}
}

return instance;
}
//end of sample code for ClassFactory

Advertisements

One Response to “Flex pattern: Set property name or type at run-time”

  1. ticaccecy Says:

    Interesting web site: hope to visit once again.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: