When to use inheritance, when to use interfaces, wrapped up in a cute example

Started by Thorin, November 19, 2009, 11:17:44 AM

Previous topic - Next topic

Thorin

Came across this on Stack Overflow, where a poster explains how to determine when to use inheritance and when to use interfaces.  I love the example!

http://stackoverflow.com/questions/90851/is-it-just-me-or-are-interfaces-overused/93998#93998
Prayin' for a 20!

gcc thorin.c -pedantic -o Thorin
compile successful

Mr. Analog

That post should be on a billboard, seriously I see these misunderstood concepts more often than I care to think.

Worst case of inheritance abuse I've seen is in the application I support, basically all business objects inherit from an extremely generic base called "document" (sigh) anyway all this has lead to is a bunch of property testing elsewhere to figure out what "kind" of "generic" object is currently being used in context. It clearly didn't occur to the programmer that even though apples, oranges and tomatoes are all "fruit" they really aren't the same thing and can't be treated as such.

To drive home the problems take a look a this kind of junk I see every day:
//@%&#ed up backwards garbage
public Slice[] Slice(Fruit fruit)
{
//Wash Fruit first
if (!(fruit is Orange))
{
wash(ref fruit);
}
else
{
peelOrange(ref fruit);
//god help you if you ever want to apply this to Apple too...
}

//Remove stem
if (fruit is Apple)
{
getRidOfAppleStem(ref fruit);
}

//Ad infinitum for every type of fruit your code is supposed to support o_O;

//slice fruit
return slice(ref fruit);
}


Now, to all of you on RW this is OBVIOUSLY backward, there should be an interface called "Fruit" that forces classes that implement it to include a Slice method where all this crap can be easily organized into context. This is a great example of someone knowing the mechanics of inheritance without understanding what it is.
By Grabthar's Hammer

Thorin

Wouldn't you have a Fruit base class and then ISliceable and IWashable and IPeelable and IContainsStem interfaces?  The Fruit base class might have a Grow() method, but there probably wouldn't be too many others.  If there are no methods that all the Fruit subclasses share, then there wouldn't be a Fruit base class.
Prayin' for a 20!

gcc thorin.c -pedantic -o Thorin
compile successful

Mr. Analog

Quote from: Thorin on December 21, 2009, 09:34:42 PM
Wouldn't you have a Fruit base class and then ISliceable and IWashable and IPeelable and IContainsStem interfaces?  The Fruit base class might have a Grow() method, but there probably wouldn't be too many others.  If there are no methods that all the Fruit subclasses share, then there wouldn't be a Fruit base class.

I guess, but that gets messy and you don't want to create a base class just to make things messy! In this situation, fruit is too diverse a subject to describe with a base object, a base interface sure, you can define attributes that describe what a fruit is or things you might do with a fruit without forcing a fruit to implement it.

Splitting up different activities into different interfaces suggests a relationship that may never exist, would there ever be a case where you would like to slice a watermelon like an apple? (Some may answer "you might" but stop and think, why make the extra work to make something that likely will never be used and may end up more confusing than useful?).

Plus you avoid getting hooked on details at too high a level, to use the grow example (good one by the way) some fruit grows on trees and some fruit grows in bushes, fruit develop in different ways, some make seeds, some don't. Basically because all this information is encapsulated in the implementation of a fruit (i.e. an orange) you just can't get generic enough at a high level without becoming mired in implementation specific details at some point or another, let alone setting them loose to be passed around.

:)

I hope that made sense, I've got a headache at the moment...
By Grabthar's Hammer