JS.Forwardable
What was it the Gang of Four said?
Prefer delegation. Delegation is the act of getting the receiver of a method call
to respond by simply passing that call along to some other object. JS.Forwardable,
a port of Ruby’s Forwardable module,
allows you to easily define instance methods that do just that.
Let’s say you have a class that wraps a collection of objects, which it stores as an array in one of its instance properties. You might implement some methods for manipulating the array through the class’ own interface:
var RecordCollection = new JS.Class({
initialize: function() {
this.records = [];
},
push: function(record) {
return this.records.push(record);
},
shift: function() {
return this.records.shift();
}
});
Instead, you can extend the class with JS.Forwardable, then use defineDelegators
to create the methods. defineDelegators takes the name of the instance property
to delegate calls to as the first argument, and the names of the delegated methods
as the other arguments:
var RecordCollection = new JS.Class({
extend: JS.Forwardable,
initialize: function() {
this.records = [];
}
});
RecordCollection.defineDelegators('records', 'push', 'shift');
var recs = new RecordCollection();
recs.push('The White Stripes - Icky Thump');
recs.push('Battles - Mirrored');
recs.shift() // -> "The White Stripes - Icky Thump"
If you need to define extra class methods, you need to change the notation slightly:
var RecordCollection = new JS.Class({
extend: [JS.Forwardable, {
// class methods go here
}],
initialize: function() {
this.records = [];
}
});
See Mixins for more info on using the extend directive.
If you want to give the delegating method a different name, use the defineDelegator
(singular) method instead:
// Add an instance method called 'add' that calls records.push
RecordCollection.defineDelegator('records', 'push', 'add');