Dmitry Filatov
Low coupling in JavaScript. Custom events 31 October 2007 |
|
Task: | Improve flexibility of the code. |
||
Each time I work on client functionality, I have to handle interrelated components. Meant by components are any objects: classes, widgets, controllers, etc. Straight-forward solution is to have component-to-component interaction strictly specified in the code. This may be effective when the connections are few, but even in such case the components will be overloaded with information about its neighborhood which is not actually supposed to be there. And when you get to the point of having many intercomponent relations, the code seems to turn into an unmanageable mess, and using it in another neighborhood is out of question.
Say, weve wrote a nice image gallery script enabling previews and animation. A click on the preview makes the full-size image appear slowly. All works finethe gallery component is complete and independent. Then we decide that while the image is crawling out, the background should change. We add the code responsible for changing background into the gallery code. And there we have the first worry signal of excess couplingthe component begins to performs something that is not its concern. The next day it appears that some of the pages must use a different background and some must not, navigation must hide and registration form must close if it was opened. Should we start adding all this into the gallery code, it becomes totally dependent on its neighborhood which is, to make it worse, also variable. So the code turns into a jumble performing way too many redundant actions. Handling this thing is no longer possible.
What can be done here? Lets consider patterns. Well make use of two: Observer and Mediator. The terms are borrowed from GoF.
This pattern implies that there are two groups of participants: Observers and Observables. The former register to observe events that may be raised by the later; Observables notify Observers when a change occurs.
Here is the Observable interface suitable for the task:
|
|
Where sEventType stands for the event and mObserver stands for the observer which can be a callback function as well as an object.
By the way, Javascript itself uses a similar model with callback function for adding event handlers to DOM elements.
Now each component using the Observable interface can recognize the events taking place. For example, the gallery could have the following events: onInit, onStartOpen, onEndOpen, onStartClose, onEndClose. When necessary, the component calls the Notify method providing information about the event, and all the registered observers receive notifications.
But how can it be that some components are to observe the events raised by other components without knowing anything about them?
In order to maintain independence of the components, its better not to use the components themselves as observers (its another kind of information burden), but have mediators, objects that already know all about the current neighborhood, its components and interrelations. This technique allows us to change mediators depending on the neighborhood which frees the component code of redundant data and makes it possible to use it another time.
The code involves arrays from the Common.js library.
|
|
To use this technique you should make Observable your base class.
If you involve Common.js, it looks like this:
|
|
If inheritance fails for some reason, you can use delegation:
|
|
And this is how you register an observer for the events raised by MyComponent:
|
|