3

I'm going through Java For Everyone by Cay Horstmann.

I'm a bit confused on when it says:

Don't Use Type Tests

This is about using instanceof operator for specific type tests in order to implement behavior that varies with each class like (taken straight from the book):

if (q instanceof ChoiceQuestions) //Don't do this
{
   //Do the task the ChoiceQuestion way
}
else if (q instanceof Question)
{
   //Do the task Question way
}

Apparently this is a poor way to do it as if you have a new class like NumericQuestion added you need to revise all parts of your program that make a type test, adding another case.

It is better to add class NumericQuestion to the program. Nothing needs to change as we are using polymorphism, not type tests. When ever you find yourself trying to use tyepe tests in a hierarchy of classes, reconsider and use polymorphism instead. Declare a method doTheTask in the superclass, override it in the subclasses and call q.doTheTask()

What I don't understand is the last paragraph, the one above. Can someone shoe me an example of what it means please? (I'm kind of a visual learner). How do we actually do this without using tyep tests?

orange
  • 5,297
  • 12
  • 50
  • 71
  • This is fundamental polymorphism -- one of the 2-3 main principles behind object-oriented programming. You need to find a few good articles on polymorphism and study them, then do some "toy" programs to experiment with them to get the concept into your brain. – Hot Licks Jan 01 '12 at 13:54

3 Answers3

1

What you should understand is that the class is responsible for its behaviour, not the calling part from the exmaple. I learned this as "a table should paint itself" principle:

Visualise furniture. You have a painter class that paints furniture, but you have to "learn" it how to paint a new type of furniture everytime you declare one. So

Painter:

if (q instanceof Table) //Don't do this
{
   //paint table
}
else if (q instanceof Closet)
{
   //paint closet
}

What you do is that you make all furniture extend a "furniture" class, that knows a method paintThySelf(). So now the painter just does

q.paintThySelf()

And if you add a Chair class, you will have to add the paintThySelf() method, and you can have it painted.

Nanne
  • 64,065
  • 16
  • 119
  • 163
1

The point is that instead of this:

if (q instanceof ChoiceQuestions) //Don't do this
{
   //Do the task the ChoiceQuestion way
}
else if (q instanceof Question)
{
   //Do the task Question way
}

you should do this:

q.doTheTask();

where the Question class contains:

public void doTheTask(String someParameter){
    //Do the task Question way
}

and the ChoiceQuestion class contains

public void doTheTask(String someParameter){
    //Do the task the  ChoiceQuestion way
}

Then, when you get a new class DrawQuestion, it will contain

public void doTheTask(String someParameter){
    //Do the task the DrawQuestionway
}

but none of the code that calls doTheTask() will have to change! There is no risk, as there is with the if (q instanceof ChoiceQuestions) pattern, of forgetting to add the new logic. And (this is actually the more important part in the long run) all the logic that concerns a specific kind of Question is concentrated in one class rather than spread out across all parts of the app.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
0

As a design principle, favour creating a subclass that has different (overridden) behaviour over using instanceof to control behaviour.

Bohemian
  • 412,405
  • 93
  • 575
  • 722