AOP is a way of changing the behaviour of existing code without modifying it. It does this by providing, what AOP calls, advice at certain join points. In plain english, it provides a way of adding additional behaviour (advice) at certain points in your program (join points). For example, adding logging functionality to your code is a standard example. Generally, you don’t want every method in your code to contain logging code. It’s not really part of the core base code. AOP provides an easy way of doing without modifying your code. But because of the way AOP works, you can add as many behaviours as you want to, to any object.
What and how?
AOP provides three aspects called before, after and around. This means that you can add additonal behaviour before, after or around certain points in your code of your own choosing. I’ve created a static class called YAHOO.Abstract.Aspect that I use to add advices to other objects. It’s a very simple one and just adds the three advices to an method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
For instance, if I wanted to add a before advice, I’d do something like the following :
After advice is similar:
Adding around advice is slightly different as you have to provide two methods, one for before and one for after:
1 2 3 4 5 6 7
All arguments are passed transparently to the original methods and for all after methods, the return value of the original method is passed in.
Let’s see how easy it is using the standard logging example. Its an simple but probably unpractical example.
This example add a simple logging behaviour for every method of a specified object. When a method is called, it is logged and so are its arguments. It also displays the methods return value, if any. For this example, it makes use of Firebug and some of its console functions, specificially group and groupEnd. These basically indent and outdent grouped console.log outputs. So how do we write the behaviour? Well, before a method is called, we want to start a new console group and also output which method was called and also any arguments if any were passed. Something like this:
1 2 3 4
Then when a method has returned we want to log that the method has returned and any return value it may returned.
1 2 3 4 5
In AOP terminology these would be termed “before” and “after” advice. But since there is also “around”, we can use that instead so we only modify each method once.
So, the full code to add this logging behaviour to any object would be like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
The above code creates a new namespace so we don’t pollute the global namespace and a new method called trace. All it does it receive a target object and adds the around advice to each method that it finds. It’s also possible to extend this so that it receives another parameter which would state a whitelist or blacklist of methods to advise (or not). The actual call to advise any object, let’s say the Dom object of YUI :
You can see the output on the example page.
What else can AOP be used for?
Profiling – very similar to the trace, but instead maintains a timing of how long each method took.
Event firing on attribute changes – if you use getters and setters and when a set method has been called, automatically fire a valueChanged custom event. In practice, can really only be used when external entities change an objects property (Its not wise for an object to call its own setter method).
Validation of methods arguments – validate passed arguments to a method, specifically setter methods though any type of method can be used.
Convertors – bridge output from one object to another incompatible object
Provide an alternate to subclassing – use mixins instead of subclassing to add more and more behaviours while reducing amount of code duplication. I’ve used this for a widget and its really useful. I hope to be posting about that in a few days.
Is it useful?
Where else is it used?