Creating a composition-based class structure using augment
Using augment
YUI().use('node', function(Y) {
// This method is in the 'oop' module. Since we require 'node'
// for this example, and 'node' requires 'oop', the 'oop' module
// will be loaded automatically.
The example: Any class can be an EventTarget
This example creates a custom class, then augments it with
EventTarget. Using the packaged functionality of EventTarget, the code for
Foo is able to focus on the functionality unique to its
purpose.
YUI().use('node', function(Y) {
// This method is in the 'oop' module. Since we require 'node'
// for this example, and 'node' requires 'oop', the 'oop' module
// will be loaded automatically.
var Foo = function() {
/* code specific to Foo */
this.publish('interestingMoment');
};
Foo.prototype.doSomething = function() {
var eventData = {};
// -- do something interesting, add results to eventData --
eventData.statusText = 'bar';
// notify the subscribers, passing the event data
this.fire('interestingMoment', eventData);
}
Y.augment(Foo, Y.EventTarget);
var foo = new Foo();
// add some event listeners
foo.on('interestingMoment', function (data) {
var p = Y.one('#demo_p1');
p.setContent('I was notified of an interesting moment: ' + data.statusText);
});
foo.on('interestingMoment', function (data) {
var p = Y.one('#demo_p2');
p.setContent('I was also notified of an interesting moment: ' + data.statusText);
});
Y.on('click', function() {
foo.doSomething();
}, '#demo');
});
Composition, not inheritance
If Foo were a part of a class hierarchy, it would be improper
to include EventTarget in the inheritance chain, because its custom event
functionality is not an intrinsic characteristic but rather an ancillary, generic
capability that many classes share.
Unlike extended classes, the relationship between a class and
the classes augmenting it is not an indication of type hierarchy. The intent
of augment is to aid in extracting nonessential behaviors or
behaviors shared by many classes, allowing for a composition-style class
architecture.
This may appear similar to multiple inheritance, but it's not.
augment simply adds the public methods and members from one class
prototype to another class prototype. Instances of the augmented class will
not pass instanceof tests for the class(es) which augmented
it.
YUI().use('oop', function(Y) {
function Foo() {}
Foo.prototype.doSomething = function () { /* something */ };
function Bar() {}
Y.augment(Bar, Foo);
var b = new Bar();
if (b instanceof Bar) {} // true
if (b instanceof Foo) {} // FALSE
});