Monday, May 14, 2007

The 'Call Super' Antipattern

A common design problem that is usually solved using the 'Call Super' antipattern (also referred to as code-smell). Simply stated, the problem occurs when the subclass needs to share the implementation of the super classes over-ridable methods.

In such case, 'Call Super' anti-patten is usually used by calling the over-ridden methods from within the subclass's over-riding methods.

I'll show a 'Call Super' code sample, then show a much better and neater solution (proposed by Martin Fowler).

The Bad Solution (Using the 'Call Super' AntiPattern):

class Penguin {
public void intoduceYourSelf() {
System.out.println("Hi, I'm classified as a penguin.");
}
}

class EmperorPenguin Extended Penguin {
public void introduceYourSelf() {
super.introduceYourSelf();
System.out.println("My real name is Emperor Penguin");
}
}
A Better Solution
A much better solution is to have an abstract method in the super class for the extra actions the subclasses will perform. And thus, the subclass only needs to implement that abstract method:

class Penguin {
public void introduceYourSelf() {
System.out.println("Hi, I'm classified as a penguin.");
talkAboutYourselfMore();
}


abstract public talkAboutYourselfMore();
}


class EmperorPenguin extends Penguin {
public void talkAboutYourselfMore() {
System.out.println("My real name is Emperor Penguin");
}
}



Thats it. A neat alternative solution that I love to use.

3 comments:

Unknown said...

This is good approach.

But when the talkAboutYourselfMore() method is abstract, the class Penguin should be abstract. Then we can't instantiate Penguin Objects.

If the case is to instantiate also the Penguin, this approach is not good. So then, do we have to use call super approach?

thank you...

Basil 3ibs said...

You can create a default implementation for method talkAboutYourselfMore() in the base class Penguin. After that you can instantiate the penguin class easily.

Adpro said...

I see this often, and a great way to get around this most of the time is to use "before" and "after" methods.

I find that most of the time when this anti-pattern comes up and is annoying is when the super.method() call is required. That's kind of the heart of the anti-pattern I think, so your example may not actually fall under this anti-pattern. It's when the super.method() call is required, and if you don't call it stuff breaks. I don't think the super.introduceYourSelf() call is required in your example, is it?

onInitliaize is a good example. I often create a base class when I'm using a class that has an onInitialize method that is used for overriding. Wicket Pages and Panels are good examples. Well, anything Wicket. I then create an abstract beforeOnInitialize and an afterOnInitialize in my extended "BasePage" class, and call these method before and after the super.onInitialize() method in my overridden onInitialize() method.

That way I can use afterOnInitialize() when I want to set up more things, without having to worry about remembering to call super.onInitialize().