Thursday, September 4, 2008

Using the Proxy class (part 1)

When I first came across the Proxy class, I got rather excited. Dreams of mock objects, cross-cuts, and various other cglib shenanigans danced in my vision. Sadly, it was not to be, and the VM doesn't let you cast Proxy as another class (or interface). However, it has its uses, and I'd like to explain how to use it.

I know it's been done before, but for this example I'm going to re-invent the "bindable dynamic object". The point is to explain the Proxy class :)

Let's get started:

[Bindable(event="propertyChange")]
public dynamic class BindableDynamic extends Proxy implements IEventDispatcher
{
    //Actual contents
    private var properties : Object = {};

    //Property names
    private var propertyNames : Array = [];

A few things here:

  1. We've annotated the class with [Bindable(event="propertyChange")]. This marks the class as bindable, and because we specify the event name, MXMLC assumes we know what we're doing and doesn't generate any Binding boilerplate for us, which is what we want :)
  2. We've got two private variables here: properties, which holds our actual values, and propertyNames, which we'll use as a list of (guess what?) property names!

The Flex docs don't use the propertyNames variable, and instead use a temporary array when iterating the fields using for..in or for each..in, but I like keeping the list around.

Some more code:

//Simple getProperty by name
override flash_proxy function getProperty(name : *) : *
{
    if (!name)
        return undefined;

    if (!(name in properties))
        return undefined;

    return properties[name];
}

//Do we have property x?
override flash_proxy function hasProperty(name : *) : Boolean
{
    return (name in properties);
}

//Set Property
override flash_proxy function setProperty(name : *, value : *) : void
{
    var oldValue : *;

    //Check for existing value
    if (name in properties)
    {
        //We do have one, we need to retrieve it for comparison and a useful PropertyChangeEvent
        oldValue = properties[name];

        //Check to see if there's no change (in which case we're out like 3 stripes)
        if (oldValue === value)
            return;
    }
    else
    {
        //If we're here, then this is a new property (not an update)
        propertyNames.push(name);
    }

    //Set property
    properties[name] = value;

    //Announce!
    dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, name, oldValue, value));
}

These functions are pretty self-explanatory. A couple of things might jump out at you if you're new(ish) to ActionScript though:

  1. The use of flash_proxy in place of private, public, or internal: In Actionscript, private, public and internal are simply namespaces (but built in and with special meaning). Proxy uses its own namespace so that its methods don't clash with anything you might be trying to intercept. You can also define your own namespaces, and there's an entire blog post (or 8) for me to write about mx_internal and the various fun stuff we can do with it!
  2. The in operator: It's not used so much, but I love its elegance. For our intent at the moment, think of it as an analogue to .hasOwnProperty(). There are differences, but for our current purpose either would do, I just prefer it stylistically. If you'd like to read more, check here and here.
  3. Finally, we dispatch our own PropertyChangeEvent, which is how we let Binding know it's time to do its thing.

…I'll post part 2 tomorrow, where we get to the fun stuff!

0 comments:

This is

  • Tales of Flex
  • From Brisbane, Australia
  • Opinions on Flex development
  • Tips and FAQs
  • Shameless self-promotion

I am

  • Twitterer
  • Flexcoder
  • Maroon
  • Designer
  • Java lover
  • That loud-mouthed Aussie yob
  • Blogger
  • Problem solver
  • Contributor
  • Cricket Fan
  • Lousy photographer
  • Great cook

I read



Subscribe via RSS to receive updates!