AS3 Property Observer Implementation

Update: The final implementation. Monday I wrote about how I would use the observer pattern to alter the functionality of getters/setters and respond to changes without using Flash’s events. Tyler and I brainstormed more about the solution and as I knew would happen we came up with a better implementation.


One thing I didn’t like about my initial go at it, is that you had to create a class with three methods, and usually you only used one of them. So methods were being called that didn’t need to be for the sake of it. We decided to add functions on an as-needed basis. I named the different types checks, hooks, and observers.

  • Check, a method which checks the validity of the data being added. If the check determines the data is invalid it returns a boolean of false. Otherwise it returns true.
  • Hook, a method which can modify the data of a setter before it gets set. This can allow formatting or other customization.
  • Observer, a method which is notified when a property has been changed. Flex uses the PropertyChange event currently.

Something Tyler didn’t like was the requirement of an interface. He wanted to be able to add the observing functionality from outside an object with a static utility class. Binding would then know if objects used the observer system with additional info in the bindable metadata [Bindable(observable)]. So I created a static utility class called Observe which would allow the logic to be handled separately. Our data-binding relies on the metadata to indicate if a given property uses Observe.


The Observe interface ended up looking like this:

public Observe { public static function addCheck(target:Object, property:String, observerHost:IEventDispatcher, observer:Function):void; public static function removeCheck(target:Object, property:String, observer:Function):void; public static function addHook(target:Object, property:String, observerHost:IEventDispatcher, observer:Function):void; public static function removeHook(target:Object, property:String, observer:Function):void; public static function addObserver(target:Object, property:String, observerHost:IEventDispatcher, observer:Function):void; public static function removeObserver(target:Object, property:String, observer:Function):void; // remove all checks, hooks, and observers from the given target public static function release(target:Object):void; // called from within the setter public static function canChange(target:Object, property:String, oldValue:*, newValue:*):Boolean; public static function modifyChange(target:Object, property:String, oldValue:*, newValue:*):* public static function notifyChange(target:Object, property:String, oldValue:*, newValue:*):void } // an example setter which hooks into the observer system public function set foo(value:String):void { var oldValue:Object = _foo; if (oldValue == value || !Observe.canChange(this, "foo", oldValue, value)) { return; } value = Observe.modifyChange(this, "foo", oldValue, value); _foo = value; Observe.notifyChange(this, "foo", oldValue, value); }

observerHost is the object the observer method belongs to. Using this allows a reference to be made to the method so that we can be completely weak-referenced and memory friendly. If the observer does not belong to an IEventDispatcher you must hold that method in a variable and pass in null to observerHost. Each check, hook, and observer can have 0-4 parameters looking like:

function foo(); function foo(value:*); function foo(oldValue:*, newValue:*); function foo(propName:String, oldValue:*, newValue:*); function foo(target:Object, propName:String, oldValue:*, newValue:*);

Checks should return a boolean, hooks should return a value, observers don’t need to return anything.

Additional functionality

By passing in “*” as the property name to any of the methods, your check, hook, or observer will be called when any property is changed on the provided object. If you pass in a class as the target to Observe.addCheck|Hook|Observer then whenever the given property is changed for any instance of that class or a subclass thereof you will be notified. For example, if you call

Observe.addObserver(Object, "*", this, myMethod);

then myMethod will be called every time any property is changed anywhere (properties that use the system that is). You can respond to any property change in the entire system that uses the property observer system I’ve created here.

Modified Flex SDK

I want to use this new observing system everywhere, but I don’t want to have to write out all the setters for it. That would take a lot of time, now and later as I write more code. So I checked out the flex4_beta2 tag from Adobe’s open source subversion repository and modified a couple of things. Now when I add [Bindable] to a property it will be observable as well as work with Flex binding. I also added the Flight binding classes so they’ll be available in all my Flex projects. I know some of you will be interested in playing with the SDK and seeing what I changed, so I’m providing a download of the modified SDK as well as the changelog. I do not plan on releasing a new modified SDK with every new Flex SDK release. I may do some for major releases, but most likely

lexapro for anxiety \\ nexium 40 mg \\ generic celebrex \\ cipro doses adults \\ cipro antibiotic \\ \\ ovule flagyl enceinte

I’ll just do it for my own use unless there gains some interest. Reflex might have it’s own SDK down the road too. So go ahead, download the SDK, create a new ActionScript Project

how does cialis work with alcohol. canada pharmacy. how often can you take viagra. cialis generic. canadian pharmacy. canadian pharmacy tampa.

called Test that uses it, and make the following your application class

package { import flash.display.Sprite; import flight.binding.Bind; import flight.observers.Observe; [Bindable] public class Test extends Sprite { public var test:String; public var test2:String; public var test3:String; public function Test() { Bind.addBinding(this, "test2", this, "test", true); test = "Hello World"; trace("test2:", test2); Observe.addHook(this, "test3", this, addNot); test3 = "I hate Flash"; trace("test3:", test3); } public function addNot(value:String):String { return value + "...NOT!"; } } }

You’ll see how hooks can work and how binding works! I haven’t tested the speed, but guaranteed this is way faster and better memory than creating a new PropertyChangeEvent object each time a property is changed. And I still have room for optimization I’ve been thinking about. I know the API will change for the setter code.

Dilemma, need your opinion

So I have a dilemma and need your feedback. Checks and Hooks could be really cool, allowing you to change stuff at run-time, inserting code into the setter as it were. However, this could also cause headache, security issues, difficult to diagnose bugs, and other potential issues. With great power comes great responsibility and jazz like that. Is it worth it? Should I remove the checks and hooks altogether and just leave observers? What are the costs, and do they out-weigh the benefits? Please comment and let me know your thoughts.


7 Responses to “AS3 Property Observer Implementation”

  1. Paul Taylor Says:

    “So I have a dilemma and need your feedback. Checks and Hooks could be really cool, allowing you to change stuff at run-time, inserting code into the setter as it were. However, this could also cause headache, security issues, difficult to diagnose bugs, and other potential issues. With great power comes great responsibility and jazz like that.”

    I could foresee a scenario where multiple hooks (for formatting or whatever) is malforming the data before its set. I could also foresee a scenario where multiple checks are added to a property incorrectly, and are preventing setting a legitimate value. Both cases should be caught by thorough unit tests, but assuming you don’t have those, maybe releaseChecks|Hooks|Observers(target:IEventDispatcher) methods could be added, just in case?

    Overall I think checks and hooks are sweet as they encourage and empower functionality composition. I vote for keeping them and including them in Reflex.

    Great ideas Jac!

  2. Max Says:

    Woohoo! I folded your Observable class into an example app I’m building at:

    I especially like the release() method, which allows one to make about-to-be-destroyed Observable classes available for garbage collection.

  3. Jacob Wright Says:

    Max: I agree about release(), but even if you don’t call it your objects will still be garbage collected. release() is a fail-proof mechanism or one you could use for object pools.

    Because of this, one problem I still want to tackle is all the checks/hooks/observers are stored in a weak-referenced dictionary, so the order in which they are called is random.

  4. karfau Says:

    Just from reading, without having used it:
    1) I very much like the idea/ implementation of Observe.
    2) I can imagine that there maybe could be a use for the checks, so keep them.
    3) I can not imagine anything where I would need/use this.

    Both checks and hooks look a bit like aspect-oriented programming to me, which I had no chance to dive into yet and which I am not sure about I more like or fear it.
    So as u said:
    “With great power comes great responsibility and jazz like that.” Yep, thats the price!

    Maybe there is a way to make those things more visible in development, e.g. by the need of implementing a class or using extra metadata or implementing Observe, CheckObserve, HookObserve, CheckHookObserve (or just Check, Hook and Observe that explicitly need to be linked together if needed)… not sure. In a way that it is easier to track the usage of it, and keep this functionality seperate / out if I don’t want to use it.
    (No idea if it is possible in a way, that is not making the code that uses it more diffucult to write… )

    Just my 2 cents,

  5. An Alternative to using PropertyChangeEvent - Jacob Wright – Flex, AIR, PHP, etc. Says:

    […] A post about a trial implementation, and the final […]

  6. Max Says:

    In my opinion, a full replacement of [Bindable] introduces quite a lot of risk. I think a new bit of custom metadata however ([Observable] perhaps?) would be a welcome addition. Thanks for sharing this great Observer implementation!

  7. Shank Says:

    Hi Jacob,

    My application needs application logging for every (add\update\delete) operations on the .mxml files. All the data providers for the list/forms are AS objects.

    I was thinking of having a function in each AS object and it should be called automatically when a property changes so that I can generate the log message.

    Your implementation seems to what I am looking for but I am not clear of how to implement it.

    Please suggest.