Inheriting methods - what to put in super class.

O

Ook

I have a class, Item. I have subclasses, CD, DVD, Book, etc (public
class Book extends Item). In the subclass Book, for example, I have a
method that returns the author of the book. I want to call this from a
class outside of the Item class, and I do it like this:

lcAuthor = item.author();

In Book I have:

public String author(){ return author; }

In Item I have the same thing. Because the method exists in Book, the
one in Item doesn't get called. This works fine. However, if I remove
the method from Item, I get a compilation error because there is no
item.author, even though there is a book.author.

I can fix this by calling item.author like this:

lcAuthor = ((Book) item).author();

This also works. My question - which should I do? Should I leave the
dummy call in my Item class that doesn't do anything? Is it better to
cast item to Book? Or is there a better way to handle this?
 
L

Lew

Ook said:
I have a class, Item. I have subclasses, CD, DVD, Book, etc (public
class Book extends Item). In the subclass Book, for example, I have a
method that returns the author of the book. I want to call this from a
class outside of the Item class, and I do it like this:

lcAuthor = item.author();

Many Java-aware tools and anything that uses JavaBeans follows a convention of
naming such a method getAuthor(). This is not mandatory, but there are a lot
of times when it's convenient to follow the convention.
In Book I have:

public String author(){ return author; }

In Item I have the same thing. Because the method exists in Book, the
one in Item doesn't get called. This works fine. However, if I remove
the method from Item, I get a compilation error because there is no
item.author, even though there is a book.author.

I can fix this by calling item.author like this:

lcAuthor = ((Book) item).author();

This also works. My question - which should I do? Should I leave the
dummy call in my Item class that doesn't do anything? Is it better to
cast item to Book? Or is there a better way to handle this?

Declare the "item" in this case to be of type Book, not Item.

This is an analysis question, more than a programming one.

When you declare a variable to be of type Item, you are essentially promising
that all that variable needs is Item stuff. It is ignorant of any subtype
behaviors or attributes.

If your logic requires a Book at some point, you have essentially lied: you
promised that your variable is only an Item, but here you "know" that it's
"really" a Book! If it's a Book that you need, then make the variable of type
Book in the first place.

Then you do not need either the downcast or to implement non-Itemish stuff in
Item.

Inheritance in object orientation models something called an "is-a" relation.
You have modeled your universe such that a Book /is-an/ Item. If you put
"author()" in Item, then your universe is such that Items have authors. (That
relationship is called "has-a".) If that is what you really mean, then put the
author attribute in Item.

OTOH, if it is not part of your universe that Items have authors, don't put
author in Item. Give Items the attributes they have, and only the attributes
they have.

For discussion, let's take author out of Item, and ignore DVDs and the rest
for a moment. Books have authors, publication dates, etc., and the Book class
extends Item. Item does not have an author attribute.

Now a Book /is-an/ Item, and additionally, it /has-a/ publication date, it
/has-an/ author, etc.

Back to your code.

Here you are at a line that wants an author. That means the logic "knows" that
you need things that have authors here. That means do not declare the variable
to be of a type (Item) that does not have an author. Use a type that knows
about having an author.

- Lew
 
Z

Zootal

When you declare a variable to be of type Item, you are essentially
promising that all that variable needs is Item stuff. It is ignorant of
any subtype behaviors or attributes.
Then how do I go about accessing book/cd/dvd specific stuff? Right now I go
through the Item, rather then directly accessing the book/cd/dvd class. All
of my book, cd, and dvd objects are subclassed from my Item class - I create
a "book" like this:

Item book = new Book( author,...)

And likewise for cds and dvds. My "library" is an ArrayList of Items. Each
item could include book, cd, or dvd attributes

I follow what you are saying, but only partially. Keep in mind that this is
a school assigment, and the structure is basically what we were given to
use. Our text also uses the same structure and similar methodology, which is
why I used it.
 
L

Lew

Then how do I go about accessing book/cd/dvd specific stuff? Right now I go
through the Item, rather then directly accessing the book/cd/dvd class. All
of my book, cd, and dvd objects are subclassed from my Item class - I create
a "book" like this:

Item book = new Book( author,...)

And likewise for cds and dvds. My "library" is an ArrayList of Items. Each
item could include book, cd, or dvd attributes

I follow what you are saying, but only partially. Keep in mind that this is
a school assigment, and the structure is basically what we were given to
use. Our text also uses the same structure and similar methodology, which is
why I used it.

Ah.

It is common for academic examples to sacrifice some good ideas in order to
focus on a particular topic.

There are times when you need a looser collection like your List<Item> where
you have to downcast, but it's always a compromise. In your situation I'd go
with the downcast, but I cannot shake the conviction that there is a layer
violation in the approach.

I am guessing that you have a set of operations on each different Item, and
that you are using the downcast type to determine what different operations to
perform. I would rather see a method inside Item that does all the logic, and
the override in each subtype that knows about things like authors.

public interface Item
{
public void store( File out );
}

public class Book extends Item
{
private String author;
public void store( File out )
{
PrintWriter wr = ... ( out ) ... ;
wr.println( "author = "+ author );
}
}

public class DVD extends Item
{
private String [] chapters;
public void store( File out )
{
PrintWriter wr = ... ( out ) ... ;
int i = 0;
for( String chapter : chapters )
{
wr.println( "chapter ["+ ++i +"] = "+ chapter );
}
}
}

public class Main
{
public static void main( String [] args )
{
File f = ...;
for ( Item item : list )
{
item.store( f );
}
}
}

Getters, setters, missing code and exception handling left as an exercise.

- Lew
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,439
Members
44,829
Latest member
PIXThurman

Latest Threads

Top