6V8 - Production of my Mind

Home page > For your Computer > Objective Degradation > Polymorphism and Inheritance

Polymorphism and Inheritance

 

In the previous tutorial: ObjectiveDegradation and Microformats, we have seen how it is simple to map XHTML structure to a javascript object and html actions to its methods using ObjectiveDegradation.

We are now going to see how this can be extended using object oriented basic principles: polymorphism and inheritance.

27 January 2006, by Mortimer

1 The example

Ok, we are now extending the hCalendar example seen before to show how ObjectiveDegradation uses javascript abilities for OO design.

This is still a dummy example, you can see the source and the test page. They rely on the previous code which shows how it is simple to extend things with OD.

2 A Different Counter: Polymorphism

So we have two Calendars object on the page, each of them have an attribute event_counter. Lets introduce a new class PowerCounter, this one, instead of incrementing one by one, multiply the counter by itself [1], so we will get:

0, 2, 4, 16, 256 ...

The new class looks like this:


PowerCounter.prototype = {
    value: 0,
    increment: function() {
        if(this.value==0) this.value = 2;
        else this.value *= this.value;
        this.updateValue();
    },
    decrement: function() {
        if(this.value==2) this.value = 0;
        else this.value = Math.sqrt(this.value);
        this.updateValue();
    },
    updateValue: function() {
        this._element.firstChild.innerHTML = this.value;
    }
};


ObjectiveDegradation.register({
    'PowerCounter': PowerCounter
});
 

All we need to change in the xhtml is the class declared for our counter in the second calendar:


<h4 class="PowerCounter event_count"><strong class="value">0</strong> events</h4>
 

instead of a simple Counter, we use a PowerCounter class. ObjectiveDegradation will therefore initialise a PowerCounter object and reference it in the work Calendar instance.

Ok, we are done. As javascript is lazy typed [2] we do not need to do anything else. As the PowerCounter exposes the same interface as the Counter class, the Calendar object can call the increment and decrement function without problem on its attribute event_count.

event_count is therefore said to be polymorph: it can either have the behaviour of a Counter or the behaviour of a PowerCounter

3 Inheritance

For all of you that have already done OOP this will seem really obvious. For the other one, lets look at the two counters code:


PowerCounter.prototype = {
    value: 0,
    increment: function() {
        if(this.value==0) this.value = 2;
        else this.value *= this.value;
        this.updateValue();
    },
    decrement: function() {
        if(this.value==2) this.value = 0;
        else this.value = Math.sqrt(this.value);
        this.updateValue();
    },
    updateValue: function() {
        this._element.firstChild.innerHTML = this.value;
    }
};

Counter.prototype = {
    value: 0,
    increment: function() {
        this.value++;
        this.updateValue();
    },
    decrement: function() {
        this.value--;
        this.updateValue();
    },
    updateValue: function() {
        this._element.firstChild.innerHTML = this.value;
    }
};
 

See? there is a lot of redundancy between the two classes, they both declare a value attribute, an updateValue method that have exactly the same «behaviour» in the two classes.

Duplicated code is always bad as it is difficult to maintain, update, review, debug, ...

This is where OO principle of inheritance comes in. In fact, the PowerCounter is just another specialisation of the Counter class and it could inherit its main caracteristics from the Counter class.

So lets simplify our code:


PowerCounter.prototype = {
    increment: function() {
        if(this.value==0) this.value = 2;
        else this.value *= this.value;
        this.updateValue();
    },
    decrement: function() {
        if(this.value==2) this.value = 0;
        else this.value = Math.sqrt(this.value);
        this.updateValue();
    },
};
 

The updateValue method and value attribute are not any more redundant as they are not mentioned. So how do you specify that PowerCounter is a sub-class of Counter?

There is no default syntax for that in javascript, but prototype.js and ObjectiveDegradation offer support for inheritance.

3.1 Class-level inheritance

Renato pointed out to me that we could easily do inheritance with the prototype.js library. In deed, we can add this simple line of code before the PowerCounter prototype declaration in our javascript file:


Object.extend(PowerCounter, Counter);
 

This will specify that all instances of the PowerCounter class are also instances of the Counter class. Therefore, they have a value attribute and an updateValue method.

3.2 Instance-level inheritance

If you use the prototype.js method to extend objects, you will extend all instances of that object. This is the common OO approach.

However, you could want this inheritance to take place only at the instance level. This can seem odd and the example of the counter is perhaps not intuitive there. But imagine that you want the PowerCounter class to be a sub-class of Counter only on some cases and a sub-class of something else in other cases.

Indeed, as an object in javascript is never strongly typed and is mutable at all time, there is no problem to add method to only one instance of an object. Which means that sometime the PowerCounter class will inherit from the Counter class, but some other time you would be free to use a different super-class.

This is a different approach from the strict inheritance model of SmallTalk, Java or C# but it allows event better code reuse, meaning lighter javascript source files and greater modularity.

With ObjectiveDegradation, an object instance is described only in the xhtml, so you will specify this inheritance at this level. All you have to do, is to specify the class attribute with the right object names in the xhtml:


<h4 class="Counter PowerCounter event_count"><strong class="value">0</strong> events</h4>
 

In this case, instead of specifying one type for the event_count attribute of our Calendar, we specify two of them. This informs ObjectiveDegradation of this inheritance tree for that specific instance.

ObjectiveDegradation looks at the class attribute from left to right. So in our case:

  1. it will create an instance of the Counter class,
  2. then it will take the PowerCounter methods and override the ones that already exist in Counter, transforming the counter in powercounter,
  3. then it will reference this new instance in the event_count attribute of the Calendar.
Date of online publication: 27 January 2006
last-update: 10 November 2006
Forum messages 0
visits:
2411

Creative Commons Attribution NonCommercial ShareAlike 2.5  License

notes

[1] I told you it was a dummy example.

[2] the type checking is done at the execution.

 

Reply to this article

 

The most read articles

Photos On Flickr

 
©
Pierre Andrews
York, uk
| Site Map | Site created with SPIP 1.9.2d [11132] | RSS | template by IZO, Mortimer. |
that the In story of
that the In story of
that the In story of
that the In story of
that the In story of