Saturday, June 18, 2005

Pr#2 Program to an Interface, not to an Implementation

We are back at the Linxemble Studios, discussing "who should fight using what"! You see two abstractions {Warrior, Weapon}. That's great! Having figured out abstractions is the key towards a successful design (Let's not discuss what's "successful" right here).


Let's look at this design:



As a usual design process, we have declared two interfaces- Warrior and Weapon. The idea is, each Warrior uses it's special Weapon. For instance, a Cavalier uses a Sword and an Archer uses a Bow. Both the Cavalier and the Archer implement the Warrior interface, while the Sword and the Bow implement the Weapon interface. To elaborate, both Cavalier and Archer implement their own set of methods (attack, getWeapon..etc.). Similarly, Both Sword and Bow implement their own "trigger" methods. Say, for the Sword the trigger means "one swipe of the word" and for the Bow it means "shooting the arrow".

Looks easy! We start implementing the specific classes like this:
Let the Cavalier contain an instance of Sword and the Archer an instance of Bow.
For now, let's just look at the Cavalier class. It contains the Sword.



So, things are implemented to some extent (in fact to quite a bit extent!), when another designer comes up with this fantastic idea of training! Here's what he has to say:

"A Cavalier normally fights with a Sword. But he can be trained to be a rifle-horseman! Let's not touch the exesting Cavalier class, as it's instances still will be in use. Let's have another class TrainedCavalier, that extends Cavalier. We need to make it contain Rifle instead of a Sword. This looks quite easy as the Rifle also is an implementer of the class Weapon and as this is an extension, we will have to override only a few methods (like attack, setWeapon) of the Cavalier, reusing the rest of the code! Isn't it?"
So, the obvious solution that comes to mind is extend the Cavalier (as it encapsulates the rest of the features, we just need to change the Weapon!).

But Arghhhhh! The TrainedCavalier class inherits an instance of Sword. This is inflexible!

To be precise, the Cavalier instantiates its Weapon as:
Sword swd ;
...
public .... setWeapon()
{
...
swd = new Sword();
...
}
Now the TrainedCavalier can NOT do this, while overriding the setWeapon method:
public .... setWeapon()
{
...
/* This is not possible, as "swd" is of type Sword,
* declared in the base class - Cavalier.
*/
swd = new Rifle();
...
}
You can go ahead and suggest you solutions to Linxemble Studios. But let's think of what could have been a better start. Had the designer of the Cavalier class used this instead:
Weapon wp;
...
public .... setWeapon()
{
...
wp = new Sword();
...
}
the TrainedCavalier could override it as:
public .... setWeapon()
{
...
/*
* This is valid, as "wp" is of type Weapon. Remember IS-A rule?
*/
wp = new Rifle();
...
}

So, the principle under the consideration "Program to an Interface, not to an Implementation"'s violated by the designer of Cavalier class, as he used the specific implementer (i.e, the Sword) of the Weapon abstraction. Now if one wants to refactor the Cavalier class (replacing the references to Sword with Weapon), he has to do so many changes in all the methods which call the methods on the Sword contained by the Cavalier. Current design of the Cavalier class done not make use of the Weapon abstraction well! Why, after all, did we force all the {Bow, Rifle, Sword} implement the interface Weapon?

Well, there is another bad thing going on, which requires us to peek into the actual code to understand it. Even after refactoring the Cavalier class, we'll see some repetition in the code across the Cavalier and Archer classes!

Well, for now, I'd say "no doctor has prescribed you to use and Interface. You may as well use an Abstract Class!".

---- Discussion to be continued...

3 Comments:

Blogger Sujeet Banerjee said...

Well, there's an error in the first UML diagram shown - the Warrior should be an "Interface", instead of the "Class" shown.

Sunday, 17 July, 2005  
Anonymous Tarun Gupta said...

I read your blog and thought I could tell you about something else which would be useful for seeing maps and directions in India.

I am writing to tell you about MapmyIndia.com, a free interactive maps and directions portal for all India. See the map of connaught place, new delhi, get directions in mumbai from nariman point to juhu airport, and find nearby ATMs in kormangala, bangalore.

As a company and individual enthusiasts, we dream only of solving the problem of reliable directions and navigation for India. For your blog specifically, you can map enable it by using our youtube-style embeddable maps, and links to specific searches (of maps, directions, local and eLocation) on MapmyIndia.

Do give us feedback, suggestions, or get involved yourself by mailing me back at tarun@mapmyindia.com or marketing@mapmyindia.com.

And if you find the different services useful, we would be grateful to you for writing and telling your readers about us.

Warm Regards,
Tarun Gupta
The MapmyIndia Team
For directions in India, just search print and go with MapmyIndia.com

Monday, 01 October, 2007  
Blogger rksistu said...

HI ,
Increase your revenue 100% of your blog by converting into free website.
Convert your blog "yourname.blogspot.com" to www.yourname.com completelyfree.
Become proud owner of the (.com) own site .
we provide you free website+ free web hosting + list of your choice of
scripts like(blog scripts,CMS scripts, forums scripts and many scripts)
all the above services are absolutely free.
You can also start earning money from your blog by referring your friends.
Please visit www.hyperwebenable.com for more info.
regards
www.hyperwebenable.com

Thursday, 19 June, 2008  

Post a Comment

<< Home