Update: Thanks to @CarstenSchwede, who pointed out that the MooTools Class Constructor expects the Extends mutator __before__ the Implements one, meaning you don’t need to worry about any of the stuff I had to come up with (described in this post). Upon further investigation with Arian, it turns out that MooTools 2.0 will NOT be dependent on order of Extends and Implements declarations in classes, thanks to this change by Kamicane.
The neverending debacle of Extends vs Implements, which one to use and how to use them together – has been a source of discomfort for me in MooTools for a while so I thought I’d write up parts of my experiences with it in the hope it may help somebody else.
I came to have a need to write a class that serves as my new mixin and brings a new method ‘kill‘ – (say, Class ninja) to another class (Class badass) that extends Class human. Pretty crazy, right?
The problem is, the pattern of:
var ninja = new Class({ kill: function() { alert("kill!"); } }); var human = new Class({ initialize: function(){ alert("i r human!"); } }); var badass = new Class({ Implements: [ninja], Extends: human, initialize: function() { alert("i r badass and.. "); this.parent(); this.kill(); } }); new badass(); // i r badass, i r human, this.kill is not a function exception.
… simply does not work. The Extend here means the human prototype is the base and it lacks the kill method. Wut?
The main practical difference in subclassing approaches is that the Implements
(mixin) does not instantiate the subclass whereas Extends
does, so there can be only one class that is extended whereas implemented ones just copy the methods from the prototypes. How to get around being able to extend a single class only? You need class human to implement ninja instead and class badass to simply extend human. Aside from the side-effect of humans getting a new kill method (which they may or may not know about), it will mean that badass will be able to use .kill as well as call upon his direct parent human.
The whole point is, you may not always be at liberty to rewrite / refactor classes the way you want them without creating complications with other parts of your web app. You could also be be extending a Mootools native class like Request.JSONP and then decide to mixin a new storage class into your extended one (true story!)…
An interesting pattern (or rather, the only pattern I have found to work… ) to overcome this goes something like this:
var ninja = new Class({ kill: function() { alert("kill!"); } }) var human = new Class({ initialize: function(){ alert("i r human!"); } }); human.implement(new ninja); var badass = new Class({ Extends: human, initialize: function() { alert("i r badass and.. "); this.parent(); this.kill(); } }); new badass(); // this.kill works.
You could even write this as:
Extends: human.implement(new ninja),
Obviously, you can simply modiy the prototype of the parent class and do:
human.implement({ kill: function() { alert("kills!"); } });
But this means the code you already have in ninja needs to be duplicated and this will go for all methods or properties you want to gain access to.
A practical example with Request.JSONP and an example caching class, created to allow use of localStorage. Why would you want to do that? Well, having a class that can allow you to cache replies from Request or Request.JSONP or anything at all is handy. And doing things that fetch non-volatile data through a rate-limited API is expensive, you are encouraged to cache. In other words, if you read a particular user’s Twitter profile / timeline, you should not have to request it again on a reload within the session. Same applies if you are expanding tiny URLs like bit.ly – the URL won’t change for any given hash so there’s no point in continuously fetching it.
In the following example, we cache the response for a user profile JSONP request via the Twitter API:
View the full fiddle here: http://jsfiddle.net/dimitar/AjP5A/.
For a real detailed explanation of Extends vs Implements in MooTools, grab a copy of Pro Javascript with MooTools by keeto.
[…] http://fragged.org/mootools-pattern-fun-class-implements-extends-at-the-same-time_1359.html http://mootools.net/docs/core/Class/Class http://stackoverflow.com/questions/1720931/mootools-extends-plus-implements […]