Downcast

J

Jarmo

I have a 3rd-party api that returns objects of class Dog. I want to add
some features to Dog but I cannot change the Dog class, nor can I change the
interface that returned me a Dog in the first place. One option might be to
write a new BigDog class that contains a Dog member and then implement
superficial getcolor(), setcolor(), getweight(), setweight() methods in
BigDog that simply call the same-named method in the contained Dog member.
But this doesn't seem to be ideal and results in me writing lots of
virtually useless code such as:

class BigDog
{
private Dog dog;
BigDog(Dog _dog)
{
dog = _dog;
}
int getcolor()
{
return dog.getcolor();
}
};

Another option might be for BigDog to extend Dog in which case I would
simply inherit the previously mentioned get/set methods with no extra code.
But in this case I don't see how to downcast, or otherwise convert, my Dog
object to a BigDog, even though all BigDogs are Dogs.

What's the best Java way to do this? Thanks.
 
E

Eric Sosman

Jarmo said:
I have a 3rd-party api that returns objects of class Dog. I want to add
some features to Dog but I cannot change the Dog class, nor can I change the
interface that returned me a Dog in the first place. One option might be to
write a new BigDog class that contains a Dog member and then implement
superficial getcolor(), setcolor(), getweight(), setweight() methods in
BigDog that simply call the same-named method in the contained Dog member.
But this doesn't seem to be ideal and results in me writing lots of
virtually useless code such as:

class BigDog
{
private Dog dog;
BigDog(Dog _dog)
{
dog = _dog;
}
int getcolor()
{
return dog.getcolor();
}
};

Another option might be for BigDog to extend Dog in which case I would
simply inherit the previously mentioned get/set methods with no extra code.
But in this case I don't see how to downcast, or otherwise convert, my Dog
object to a BigDog, even though all BigDogs are Dogs.

What's the best Java way to do this? Thanks.

I think you want to extend Dog. When you know that
a particular Dog happens to be a BigDog, you can convert
the reference with a cast:

Dog dog = DogPound.adopt();
dog.bark(); // all Dogs do this
dog.shed(); // all Dogs do this
if (dog.getWeight() >= BigDog.MINIMUM_WEIGHT) {
/* not just a Dog, but also a BigDog */
BigDog behemoth = (BigDog)dog;
behemoth.terrify(postman); // only BigDogs do this
behemoth.sitOnAndBreak(sofa); // only BigDogs do this
}

You can also use `instanceof' to test whether a
particular Dog is also a BigDog, but the accepted wisdom
is that if you find yourself doing this a lot you should
probably re-think your design.

Of course, you can't just convert any arbitrary Dog
to a BigDog:

Dog dog = DogPound.adopt(Dog.PAPILLON);
BigDog behemoth = (BigDog)dog; // ClassCastException

.... but that's not a drawback; it's the natural order of
things. A BigDog is a specialized Dog, and a Dog that
lacks those specializations isn't a BigDog and can't be
treated as one. All BigDogs are Dogs, but some Dogs are
not BigDogs.
 
D

David Hilsee

Jarmo said:
I have a 3rd-party api that returns objects of class Dog. I want to add
some features to Dog but I cannot change the Dog class, nor can I change the
interface that returned me a Dog in the first place. One option might be to
write a new BigDog class that contains a Dog member and then implement
superficial getcolor(), setcolor(), getweight(), setweight() methods in
BigDog that simply call the same-named method in the contained Dog member.
But this doesn't seem to be ideal and results in me writing lots of
virtually useless code such as:

class BigDog
{
private Dog dog;
BigDog(Dog _dog)
{
dog = _dog;
}
int getcolor()
{
return dog.getcolor();
}
};

If you use an IDE that can automatically generate delegate methods (like
Eclipse, for example), then this isn't a big pain. The other option is to
write one getDog() method that returns the private dog instance.
Another option might be for BigDog to extend Dog in which case I would
simply inherit the previously mentioned get/set methods with no extra code.
But in this case I don't see how to downcast, or otherwise convert, my Dog
object to a BigDog, even though all BigDogs are Dogs.

You might be able to make the BigDog's base Dog instance have all the same
properties of an arbitrary Dog instance by calling every getter from the
arbitrary instance and invoking the corresponding setters on the base
instance.
 
S

Sam

Jarmo said:
I have a 3rd-party api that returns objects of class Dog. I want to add
some features to Dog but I cannot change the Dog class, nor can I change the
interface that returned me a Dog in the first place. One option might be to
write a new BigDog class that contains a Dog member and then implement
superficial getcolor(), setcolor(), getweight(), setweight() methods in
BigDog that simply call the same-named method in the contained Dog member.
But this doesn't seem to be ideal and results in me writing lots of
virtually useless code such as:

class BigDog
{
private Dog dog;
BigDog(Dog _dog)
{
dog = _dog;
}
int getcolor()
{
return dog.getcolor();
}
};

Another option might be for BigDog to extend Dog in which case I would
simply inherit the previously mentioned get/set methods with no extra code.
But in this case I don't see how to downcast, or otherwise convert, my Dog
object to a BigDog, even though all BigDogs are Dogs.

What's the best Java way to do this? Thanks.

Assuming you want to use the same instance of Dog returned by the
interface, then I think you're stuck with the delegation solution.
There are a lot of advantages to using delegation over inheritance
anyway, see "Effective Java" by Joshua Bloch.

Sam90
 
T

thufir.hawat

On 21 Jul 2004, Sam wrote:
[..]
Assuming you want to use the same instance of Dog returned by the
interface, then I think you're stuck with the delegation solution.
There are a lot of advantages to using delegation over inheritance
anyway, see "Effective Java" by Joshua Bloch.

Sam90

IIRC one of the first section's entitled "prefer composition over
inheritance," I don't recall a specific section detailing delegation.
Would you expand on your suggestion, please?


Thufir Hawat
 
J

Jarmo

Sam said:
Assuming you want to use the same instance of Dog returned by the
interface, then I think you're stuck with the delegation solution.
There are a lot of advantages to using delegation over inheritance
anyway, see "Effective Java" by Joshua Bloch.

Sam90

Thanks everyone for the responses. Some work for me to do now.
 

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

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top