Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Class hierarchy design question

0 views
Skip to first unread message

cio...@yahoo.it

unread,
Nov 20, 2003, 10:03:11 AM11/20/03
to
I have a problem with class hierarchy design. Here is the example:

class FruitsList
{

}

class ApplesList extends FruitsList
{

}

class OrangesList extends FruitsList
{

}

class FruitsListPerGarden extends FruitsList
{
// code
}

How can I implements ApplesListPerGarden and OrangesListPerGarden without
duplicate code from FruitsListPerGarden?

Thanks in advances,

Alex

Alex

unread,
Nov 20, 2003, 12:35:22 PM11/20/03
to
cio...@yahoo.it wrote:

> I have a problem with class hierarchy design. Here is the example:
>
> class FruitsList
> {
>
> }
>
> class ApplesList extends FruitsList
> {
>
> }
>
> class OrangesList extends FruitsList
> {
>
> }
>
> class FruitsListPerGarden extends FruitsList
> {
> // code
> }

Sorry, the example is wrong. The last class definition would be:

class ApplesListPerGarden extends ApplesList
{
// code
}

I would write a OrangesListPerGarden class without duplicate the code in
ApplesListPerGarden class. I don't have to extend from FruitsList but from
ApplesList.


Thanks in advances,

Alex

H. S. Lahman

unread,
Nov 20, 2003, 4:24:14 PM11/20/03
to
Responding to Cioelle...

That can't be answered without more context about the /real/ problem
being solved. You have provided a contrived example of a particular
solution and ask how to fix it rather than asking what the solution
should be to your problem.

FWIW, this screams that one should not be abstracted in a hierarchy.
That's because Gardens and Fruits are quite different things. Kind of
apples and oranges. B-) It seems much more likely that you need
something like:

1 *
[Garden] ----------------- [FruitsList]
A
|
+------+-------+
| |
[ApplesList] [OrangesList]

However, without more specific problem space information one can't say.

*************
There is nothing wrong with me that could
not be cured by a capful of Drano.

H. S. Lahman
h...@pathfindermda.com
Pathfinder Solutions -- Put MDA to Work
http://www.pathfindersol.com
(888)-OOA-PATH


Doc O'Leary

unread,
Nov 20, 2003, 6:30:28 PM11/20/03
to
In article <bpil1r$51j$1...@news.ngi.it>,
"cio...@yahoo.it" <cio...@yahoo.it> wrote:

> I have a problem with class hierarchy design. Here is the example:

Wow, that's a real crappy example. I'm not sure what design issue
you're even trying to address. Perhaps you could explain your design
goal instead of giving a bad implemenation? As it stands, it looks like
you want to have lists of particular fruits that a garden contains. If
that is the case, trying to base it all on the root class of FruitsList
is a really bad idea. From a design perspective, it would seem to make
more sense to have a Garden object that can return List objects of the
types of Fruit objects it contains.

Rod Davison

unread,
Nov 20, 2003, 8:08:24 PM11/20/03
to
Just picked up this thread. A generic programming solution using
templates suggest is self.

Without too much background, I might suggest
the following more classical OO reanalysis

// things that can be put into a fruitList
abstract class fruit {}

// concrete fruits

class apples extends fruit{}
class oranges extends fruit{}

// class that encapsulates all the functionality of being a list of fruits
class fruitList {
fruit listImplementation[];
}

class fruitListperGarden extends fruitList {}

If you want to create a specific appleList (again, this is where a
parameterized class is handy), we might add something like

class fruitList {
public fuitList (String type) { this.type = type}

public void addFruit (fruit f) {
if (f.type != this.type) throw new WrongFruitException();
}

}

You get the idea. You can also use a decorator pattern to get the same
effect as the above. I would still tend to use parameterized calsses
though.

On Thu, 20 Nov 2003 21:24:14 +0000, H. S. Lahman wrote:

> Responding to Cioelle...
>
>> I have a problem with class hierarchy design. Here is the example:
>>
>> class FruitsList
>> {
>>
>> }
>>
>> class ApplesList extends FruitsList
>> {
>>
>> }
>>
>> class OrangesList extends FruitsList
>> {
>>
>> }
>>
>> class FruitsListPerGarden extends FruitsList
>> {
>> // code
>> }
>>
>> How can I implements ApplesListPerGarden and OrangesListPerGarden without
>> duplicate code from FruitsListPerGarden?

--
.................................................
Why isn't phonetic spelled the way it sounds?

Rod Davison - Critical Knowledge Systems Inc.

Alex

unread,
Nov 21, 2003, 4:53:11 AM11/21/03
to
Rod Davison wrote:

> Just picked up this thread. A generic programming solution using
> templates suggest is self.
>
> Without too much background, I might suggest
> the following more classical OO reanalysis
>
> // things that can be put into a fruitList
> abstract class fruit {}
>
> // concrete fruits
>
> class apples extends fruit{}
> class oranges extends fruit{}
>
> // class that encapsulates all the functionality of being a list of fruits
> class fruitList {
> fruit listImplementation[];
> }
>
> class fruitListperGarden extends fruitList {}

Thank you for your reply. Your solution can solve my problem, but I'm using
a database to store fruits. In the class FruitsList I get the list of
fruits by a query like "SELECT * FROM fruits". How can I separate Fruit and
FruitsList classes in this case?

Thanks,

Alex


Rick Elbers

unread,
Nov 21, 2003, 7:10:47 PM11/21/03
to
Alex,

Interestingly enough this is where templates and template libraries
are designed for..:-)
Inheritance from composites in not always a very good idea, especially
not if you talk about a basic container like a list.
Have Apple and Orangage be a Fruit so that both can be in FruitList,
have a Garden which has Fruits, or if you want it: two Fruits

Rick Elbers

Rick Elbers

unread,
Nov 21, 2003, 7:12:55 PM11/21/03
to

Simply by following a basic DM mapping. Let every persistant class has
its own DMClass. In this case DMFruit. This DMFruit can give you both
a Fruit( by id and type for instance) and also the whole list( ) and
also a list by type.

Rick Elbers


>Alex
>
>
>
>

Uncle Bob (Robert C. Martin)

unread,
Nov 27, 2003, 9:01:05 AM11/27/03
to
"cio...@yahoo.it" <cio...@yahoo.it> might (or might not) have
written this on (or about) Thu, 20 Nov 2003 16:03:11 +0100, :

This is a classic violation of the Liskov Substitution Principle.
This principle says a subtype is substitutable for its base type.
Clearly ApplesList is not substitutable for FruitsList. The reason is
that users of FruitsList are within their rights to add Oranges to the
FruitsList. If you pass an ApplesList to such a user, it will get
confused.

This is one of the problems with the "ISA" test for inheritance. The
test isn't very reliable. The ISA test allows you to add constraints
to derivative types; whereas good design principles prohibit such
increased constraints.

See the "Design Principles" papers at www.objectmentor.com.

I'm not quite sure I understand the issue with FruitsListPerGarden.
What is it that you are trying to accomplish?


Robert C. Martin | "Uncle Bob"
Object Mentor Inc. | unclebob @ objectmentor . com
501 N. Riverside Dr.| Tel: (800) 338-6716
Suite 206 | Fax: (847) 775-8174 | www.objectmentor.com
| | www.XProgramming.com
Gurnee, IL, | Training and Mentoring | www.junit.org
60031 | OO, XP, Agile, C++, Java, C# | http://fitnesse.org

Ryan Kinderman

unread,
Dec 8, 2003, 1:23:57 AM12/8/03
to

Uncle Bob (Robert C. Martin) wrote:
> This is a classic violation of the Liskov Substitution Principle.
> This principle says a subtype is substitutable for its base type.
> Clearly ApplesList is not substitutable for FruitsList. The reason is
> that users of FruitsList are within their rights to add Oranges to the
> FruitsList. If you pass an ApplesList to such a user, it will get
> confused.

Actually, the Liskov Substitution Principle says that "*Functions* that
use pointers or references to base classes must be able to use objects
of derived classes without knowing it."

It seems to me that, by this definition, the only requirement is that if
you have a function that takes, as an argument, an instance of
FruitList, the function should only operate on generic FruitList
instances, and not be concerned with the specific type of fruit
contained therein. I'm assuming that AppleList and OrangeList exist
because there is a need for some strongly-typed FruitList functionality.
Perhaps, for instance, the FruitList class has an Item(int index)
operation that returns a Fruit object, but does not implement an Add()
operation. The strongly-typed AppleList class implements Add(anApple),
to force a client to add the correct type of Fruit (the same would be
true for OrangeList).

In the case I've described, perhaps a function exists that does not need
to add fruits to the list, but simply access them for some purpose,
without concern for the specific kind of fruit. To that end, the
function takes as an argument a FruitList class. With my understanding
of the Liskov principle, it seems that a violation would only occur if
that function had to cast the list argument to a specific kind of
FruitList, as this would mean that the function had to know which kind
of FruitList was passed in as an argument.

Is this a correct understanding of the principle, or am I missing something?

Thanks


Ryan Kinderman

Phlip

unread,
Dec 8, 2003, 2:10:05 AM12/8/03
to
Ryan Kinderman wrote:

> Uncle Bob (Robert C. Martin) wrote:

> > This is a classic violation of the Liskov Substitution Principle.
> > This principle says a subtype is substitutable for its base type.
> > Clearly ApplesList is not substitutable for FruitsList. The reason is
> > that users of FruitsList are within their rights to add Oranges to the
> > FruitsList. If you pass an ApplesList to such a user, it will get
> > confused.
>
> Actually, the Liskov Substitution Principle says that "*Functions* that
> use pointers or references to base classes must be able to use objects
> of derived classes without knowing it."

There is nothing else (in OO-land) that can use handles to base classes.
Functions are implied. Users of FruitsList, meaning functions passed handles
to FruitsLists, may expect permission to add Oranges, if they have
permission to add anything.

> It seems to me that, by this definition, the only requirement is that if
> you have a function that takes, as an argument, an instance of
> FruitList, the function should only operate on generic FruitList
> instances, and not be concerned with the specific type of fruit
> contained therein. I'm assuming that AppleList and OrangeList exist
> because there is a need for some strongly-typed FruitList functionality.
> Perhaps, for instance, the FruitList class has an Item(int index)
> operation that returns a Fruit object, but does not implement an Add()
> operation. The strongly-typed AppleList class implements Add(anApple),
> to force a client to add the correct type of Fruit (the same would be
> true for OrangeList).

That's a good way to enforce LSP! Only client function who bind to a derived
type can access the Add() method. All functions who bind to the base type
must expect any Fruit.

That fits the Design by Contract maxim, "A derived function may not add to a
base function's entry conditions, nor retract an exit condition."

If Add() were in the base type, the Add() for the derived type AppleList
would need an exit condition invariant "I only contain Apples" (even if that
function were only inherited by implementation, and not re-written in the
derived class). But that derived invariant would retract the base class's
Add() method's invariant "I may contain any fruit".

By that analysis, Add() can't exist in the base because its invariants
wouldn't be coherent.

> In the case I've described, perhaps a function exists that does not need
> to add fruits to the list, but simply access them for some purpose,
> without concern for the specific kind of fruit. To that end, the
> function takes as an argument a FruitList class. With my understanding
> of the Liskov principle, it seems that a violation would only occur if
> that function had to cast the list argument to a specific kind of
> FruitList, as this would mean that the function had to know which kind
> of FruitList was passed in as an argument.
>
> Is this a correct understanding of the principle, or am I missing
something?

Your understanding is very close to the known envelop here; more important,
it will guide you to good designs.

A very simple rule of thumb: Don't typecast. Cleaning them out of a design
tends to improve it - with much less analysis.

Of course that rule can swiftly lead to abandoning Java and C#...

--
Phlip
http://www.greencheese.org/LucidScheming
-- The plasma signature at the end of the
wormhole is an approaching warbird --


0 new messages