valid use of instanceof or a better way?

V

VisionSet

Usually we prefer to avoid instanceof and just call objects by their
interface type for example and use the fact that the various classes will
have implemented the method appropriately.

I have 10 subclasses directly extending Super and all implement a method
doSomething()

eg

class SubA extends Super {

void doSomething(Super arg) {

if(arg instanceof SubA) //do something
if(arg instanceof SubB) //do something
if(arg instanceof SubC) //do something
}
}

Each subclass has something similar, but the something that they do can not
be done in a generic way because it depends on which subclass instigates it.

I don't think I can do this in any other way than instanceof or
Class.isInstance()

Or... am I having a stupid day again?
 
E

Eric Sosman

VisionSet said:
Usually we prefer to avoid instanceof and just call objects by their
interface type for example and use the fact that the various classes will
have implemented the method appropriately.

I have 10 subclasses directly extending Super and all implement a method
doSomething()

eg

class SubA extends Super {

void doSomething(Super arg) {

if(arg instanceof SubA) //do something
if(arg instanceof SubB) //do something
if(arg instanceof SubC) //do something
}
}

Each subclass has something similar, but the something that they do can not
be done in a generic way because it depends on which subclass instigates it.

I don't think I can do this in any other way than instanceof or
Class.isInstance()

Ordinarily one would implement a doSomething() method in
each class, and put the class-specific operations there. Then
you could just write `arg.doSomething()' and let Java figure
out which actual method to run.

This requires that Super also have a doSomething() method.
You could plant some shared code there, or declare the method
(and hence Super itself) `abstract', or whatever makes sense.

If there's something about your situation that discourages
the use of this "plain vanilla" approach, I'm failing to see
it. Perhaps a less generic explanation is needed ...
 
V

VisionSet

Eric Sosman said:
Ordinarily one would implement a doSomething() method in
each class, and put the class-specific operations there. Then
you could just write `arg.doSomething()' and let Java figure
out which actual method to run.

This requires that Super also have a doSomething() method.
You could plant some shared code there, or declare the method
(and hence Super itself) `abstract', or whatever makes sense.

If there's something about your situation that discourages
the use of this "plain vanilla" approach, I'm failing to see
it.

The point I'm trying to make is that what doSomething() does, does not
depend just on the subclass it is part of, it also depends on the argument
to its method which is itself an instance of *one* of these subclasses, it
is the declared type of this argument that affects the behaviour of the
doSomething() method.
Perhaps a less generic explanation is needed ...


class Mouse extends Animal {

void carry(Animal animal) {
if(animal instanceof Mouse) // carry protesting
if(animal instanceof Fish) // fish slides off
if(animal instanceof Dog) // flat mouse
}

class Fish extends Animal {

void carry(Animal animal) {
if(animal instanceof Mouse) // mouse drowns
if(animal instanceof Fish) // fish slides off
if(animal instanceof Dog) // dog decides to swim for it
}

class Dog extends Animal {

void carry(Animal animal) {
if(animal instanceof Mouse) // dog unaware
if(animal instanceof Fish) // fish becomes matted in long hair
if(animal instanceof Dog) // dogs fight
}
 
J

John C. Bollinger

VisionSet said:
Usually we prefer to avoid instanceof and just call objects by their
interface type for example and use the fact that the various classes will
have implemented the method appropriately.

I have 10 subclasses directly extending Super and all implement a method
doSomething()

eg

class SubA extends Super {

void doSomething(Super arg) {

if(arg instanceof SubA) //do something
if(arg instanceof SubB) //do something
if(arg instanceof SubC) //do something
}
}

Each subclass has something similar, but the something that they do can not
be done in a generic way because it depends on which subclass instigates it.

I don't think I can do this in any other way than instanceof or
Class.isInstance()

Or... am I having a stupid day again?

I think you're having a bad design day. Either Super represents too
generic an abstraction, or the subclasses represent too specific
abstractions, or there is a better way. I would need more details to
decide which.

Consider what it is that Super represents, and what it means for a Super
to doSomething to another Super. It may be that you need to define one
or more additional methods on Super that subclasses can override to fill
in the details that instances other subclasses need in order to
doSomething. (That would constitute an implementation of the Template
Method pattern, for those keeping score at home. :) )


John Bollinger
(e-mail address removed)
 
E

Eric Sosman

VisionSet said:
The point I'm trying to make is that what doSomething() does, does not
depend just on the subclass it is part of, it also depends on the argument
to its method which is itself an instance of *one* of these subclasses, it
is the declared type of this argument that affects the behaviour of the
doSomething() method.


class Mouse extends Animal {

void carry(Animal animal) {
if(animal instanceof Mouse) // carry protesting
if(animal instanceof Fish) // fish slides off
if(animal instanceof Dog) // flat mouse
}

class Fish extends Animal {

void carry(Animal animal) {
if(animal instanceof Mouse) // mouse drowns
if(animal instanceof Fish) // fish slides off
if(animal instanceof Dog) // dog decides to swim for it
}

class Dog extends Animal {

void carry(Animal animal) {
if(animal instanceof Mouse) // dog unaware
if(animal instanceof Fish) // fish becomes matted in long hair
if(animal instanceof Dog) // dogs fight
}

Thanks for the illustration; I now think I see where you're
heading. However, "where you're heading" is probably "a nice
place to visit, but you wouldn't want to live there."

... that is to say, you could use `instanceof' to implement
this scheme, but you may come to regret it. When you decide to
add a Bird class, you'll not only need to write four behaviors
for Bird itself, but you'll also need to revisit the existing
Mouse, Fish, and Dog classes and teach them about Bird. And
then along come Snake and Cat and Armadillo -- you've got an
N-by-N matrix of behaviors, and the components of the matrix
are scattered across N different classes, all mutually aware.
This is the kind of maintenance headache that object-oriented
design (more specifically, encapsulation) is supposed to cure.

Can you redesign the model to give that N-by-N behavior
matrix a "life of its own," as it were? That is, could the
various behaviors be objects in their own right, managed in
one class (or one tree of classes) instead of strewn all over
the landscape?
 
H

Harald Hein

VisionSet said:
The point I'm trying to make is that what doSomething() does, does
not depend just on the subclass it is part of, it also depends on
the argument to its method which is itself an instance of *one* of
these subclasses, it is the declared type of this argument that
affects the behaviour of the doSomething() method.

Use method overloading, do what is called a double-dispatch, and/or if
you have more than one special thing to do, consider the visitor design
pattern.
 
V

VisionSet

I think you're having a bad design day.
Correct!

Either Super represents too
generic an abstraction, or the subclasses represent too specific
abstractions, or there is a better way. I would need more details to
decide which.

Consider what it is that Super represents, and what it means for a Super
to doSomething to another Super. It may be that you need to define one
or more additional methods on Super that subclasses can override to fill
in the details that instances other subclasses need in order to
doSomething. (That would constitute an implementation of the Template
Method pattern, for those keeping score at home. :) )

Yes of course that makes sense, annoying I didn't spot that since it was the
1st pattern I learnt to use, and before I even realised it was one.

Thanks
 
M

Michiel Konstapel

The point I'm trying to make is that what doSomething() does, does not
depend just on the subclass it is part of, it also depends on the
argument
to its method which is itself an instance of *one* of these subclasses,
it
is the declared type of this argument that affects the behaviour of the
doSomething() method.



class Mouse extends Animal {

void carry(Animal animal) {
if(animal instanceof Mouse) // carry protesting
if(animal instanceof Fish) // fish slides off
if(animal instanceof Dog) // flat mouse
}

class Fish extends Animal {

void carry(Animal animal) {
if(animal instanceof Mouse) // mouse drowns
if(animal instanceof Fish) // fish slides off
if(animal instanceof Dog) // dog decides to swim for it
}

class Dog extends Animal {

void carry(Animal animal) {
if(animal instanceof Mouse) // dog unaware
if(animal instanceof Fish) // fish becomes matted in long hair
if(animal instanceof Dog) // dogs fight
}

You can use a construct like the following. I think it's called "double
dispatch". It still requires knowledge about the existing subclasses but
you're gonna have that anyway with interactions like this, and it doesn't
require use of instanceof.
abstract class Animal {
void carry(Animal animal) {
animal.beCarried(this);
}
abstract void carryMouse(Mouse mouse);
abstract void carryDog(Dog dog);
abstract void carryFish(Fish fish);
}
class Mouse extends Animal {
void carryMouse(Mouse mouse) {
protest();
}
void carryFish(Fish fish) {
fish.slideOff();
}

void carryDog(Dog dog) {
splat();
}
void beCarried(Animal animal) {
animal.carryMouse(this);
}
}
class Fish extends Animal {
void carryMouse(Mouse mouse) {
mouse.drown();
}
void carryFish(Fish fish) {
fish.slideOff();
}

void carryDog(Dog dog) {
dog.swim();
}
void beCarried(Animal animal) {
animal.carryFish(this);
}
}
...
This has the downside that you basically need to enumerate all the
subclasses in the base class.
Michiel
 
V

VisionSet

Plenty to think about, thanks all.
I'm sure I'll do the right thing when I know more about what I'm dealing
with.
 
V

VisionSet

You can use a construct like the following. I think it's called "double
dispatch". It still requires knowledge about the existing subclasses but
you're gonna have that anyway with interactions like this, and it doesn't
require use of instanceof.
abstract class Animal {
void carry(Animal animal) {
animal.beCarried(this);
}
abstract void carryMouse(Mouse mouse);
abstract void carryDog(Dog dog);
abstract void carryFish(Fish fish);
}
class Mouse extends Animal {
void carryMouse(Mouse mouse) {
protest();
}
void carryFish(Fish fish) {
fish.slideOff();
}

void carryDog(Dog dog) {
splat();
}
void beCarried(Animal animal) {
animal.carryMouse(this);
}
}
...
This has the downside that you basically need to enumerate all the
subclasses in the base class.

Not quite sure of the advantages of this over instanceof.
If I add another subclass, I still need to alter all the classes.

I think perhaps the only ways to avoid this is either model the actual
behaviours as Eric has suggested, or have a more elaborate inheritence
hierachy that factors out behaviours up the heierachy. Maybe this is one
and the same thing or could involve implementing a behaviour interface from
an interface hierachy.
 
A

ak

don't use instanceof at all!
class Mouse extends Animal {

void carry(Animal animal) {
if(animal instanceof Mouse) // carry protesting
if(animal instanceof Fish) // fish slides off
if(animal instanceof Dog) // flat mouse
}

class Mouse extends Animal {
void carry(Mouse mouse) {
// carry protesting
}

void carry(Fish fish) {
// fish slides off
}

void carry(Dog dog) {
// flat mouse
}
}
 
C

Christophe Vanfleteren

VisionSet said:
Yes of course that makes sense, annoying I didn't spot that since it was
the 1st pattern I learnt to use, and before I even realised it was one.

Thanks

An alternative pattern is the Strategy pattern. It is somewhat more flexible
than the Template method pattern (you don't need the concrete inheritance,
but since you have this anyway in this case, it may not matter).
 
A

Adam

Not quite sure of the advantages of this over instanceof.
Using instanceof won't prevent from compiling unfinished
application (where not all behaviours are implemented).
If you use Visitor pattern it is compiler resposibility to tell
you what's missing. Huge advantage in your situation,
with so many subclasses.
Moreover instanceof is slower than polymorphic call.
If I add another subclass, I still need to alter all the classes.
It may be a drawback... but still, it makes
perfect sense to me to define interacion between an object
of class A and any other object - in class A.
A Cat knows how to handle Mouse or Dog, noone else.

But if you plan to do some incremental programming,
like adding new classes in a longer period of time,
this can be a pain in the ass to change each class each time you
add something new. Even though the compiler will tell you
where you should add some behaviour.

regards,
Adam
 
D

Dale King

ak said:
don't use instanceof at all!


class Mouse extends Animal {
void carry(Mouse mouse) {
// carry protesting
}

void carry(Fish fish) {
// fish slides off
}

void carry(Dog dog) {
// flat mouse
}
}


That doesn't work. For overloaded methods the choice of which method to call
is based on the compile-time type of the parameter not the run-time type of
the object that is referenced. So if I have:

Mouse m = new Mouse();
Animal fish = new Fish();
m.carry( fish );

That will not call carry( Fish ). It will try to call carry( Animal ) (or
carry with any super class or super interface of Animal). If that is not
defined it will not even compile. It will work in combination with the
double dispatch pattern or visitor pattern however.
 

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,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top