Two inheritence hierachies are associated - Cast or Hide ?

Discussion in 'Java' started by VisionSet, Oct 21, 2004.

  1. VisionSet

    VisionSet Guest

    Person-------->Dog
    ^ ^
    | |
    Male--------->ButchDog

    Person has a Dog
    Male has a ButchDog

    If I want to call the Dog types from the Person types polymorphically is it
    best style to cast for each call or hide the Dog type with the ButchDog type
    in Male with an instance variable eg:

    public class A {

    X z;

    public A(X x) {
    z = x;
    }

    public void doStuff1()
    z.stuff();
    }
    }

    class B extends A {

    Y z;

    public B(Y y) {
    super(y);
    z = y;
    }

    public void doStuff2()
    z.stuff();
    }

    }

    class X {
    public void stuff() {}
    }

    class Y extends X {
    public void stuff() {}
    }

    // OR...

    public class A {

    X z;

    public A(X x) {
    z = x;
    }

    public void doStuff1()
    z.stuff();
    }
    }

    class B extends A {

    public B(Y y) {
    super(y);
    }

    public void doStuff2()
    ((Y) z).stuff();
    }

    }

    TIA
     
    VisionSet, Oct 21, 2004
    #1
    1. Advertisements

  2. Neither. If Dog is polymorphic with respect to the method(s) you want
    to invoke then you don't have to cast or store multiple references, nor
    do you have to create different methods on Person and Male. Just invoke
    the polymorphic method via Person's reference to the relevant Dog,
    without caring what _kind_ of Dog it might be. That's the essence of
    polymorphism. See example below.
    So far, so good.
    Ack! Don't do this. Hiding an instance variable is messy and
    confusing. Hiding it with a differently-typed reference to the same
    object is just ugly.
    This is pointless. If b is a reference to an instance of B, then
    b.doStuff1() has exactly the same result as b.doStuff2().
    As before, if b is a B, then b.doStuff1() has exactly the same effect as
    b.doStuff2(). You would only need to cast if you wanted to invoke a
    method Y.stuff2(), defined for Y but not for X.
    You're making it all too hard. Try this on for size (using definitions
    above for X and Y):

    public class A {

    X z;

    public A(X x) {
    z = x;
    }

    public void doStuff()
    z.stuff();
    }
    }

    class B extends A {
    public B(Y y) {
    super(y);
    }

    // no other code needed
    }


    John Bollinger
     
    John C. Bollinger, Oct 21, 2004
    #2
    1. Advertisements

  3. VisionSet

    VisionSet Guest

    Suspected so.
    You've missed my point, probably my fault.
    The point is that there is not an overridden doStuff() (hence the doStuff 1
    & 2). I want to call subclass (Y) specific methods from B. So I do need to
    cast or keep reference to the subclass somewhere.

    I realise the polymorphic ripple you have illustrated.
     
    VisionSet, Oct 21, 2004
    #3
  4. Ah, I see. I was confused by the use of "stuff" to refer to both a
    general X method and a (distinct) Y-specific one. In that case, cast.
    If you like, you can create a method to do it for you (e.g. ButchDog
    getDogAsButchDog()); that might be particularly appealing if you are
    already self-encapsulating anyway, and/or if you don't want class A to
    expose its member variable directly.


    John Bollinger
     
    John C. Bollinger, Oct 21, 2004
    #4
  5. VisionSet

    VisionSet Guest

    Perfect, thanks!
     
    VisionSet, Oct 22, 2004
    #5
  6. VisionSet

    VisionSet Guest

    Actually, something else...

    This is all very well when you have a class to put method body in to do the
    cast but if you have interfaces you end up with this sort of thing:

    interface Dog {

    Bone getBone();
    }

    interface ButchDog extends Dog {

    ButchBone getButchBone();
    }

    ButchBone being a subclass of Bone

    I suspect Tiger addresses this, but how would you address it otherwise,
    since ButchDog is now a confusing interface.
     
    VisionSet, Oct 22, 2004
    #6
  7. VisionSet

    xarax Guest

    I have no problem with interface hierarchies. The
    above hierarchy appears quite often in my applications.
    Mostly for extending the Iterator interface:

    public interface FubarIterator
    extends Iterator
    {
    public abstract Fubar nextFubar();
    }

    public abstract class FubarIteratorAbstract
    implements FubarIterator
    {
    public Fubar nextFubar()
    {
    return /* the next Fubar instance */;
    }

    public Object next()
    {
    return nextFubar();
    }

    /* All of the other stuff needed for implementation. */
    }

    The Iterator interface has a method next() that
    returns Object. I use the subinterface to return
    the specific type that I want from the Iterator.
    The design greatly reduces casts appearing in
    the application. The casts are hidden behind the
    interface methods. In the above example, the
    implementation of the next() method of Iterator
    simply passes the call to nextFubar().

    Generics (J2SE 5.0) may help to alleviate the casts
    for most of the Collections interfaces and classes.
    I would only use generics where it helps readability
    and understandability, because the compiler inserts
    invisible casts. Casts can clutter the source code,
    but they make it plainly clear what is the programmer's
    intent.

    Two cents worth. Your mileage may vary.
     
    xarax, Oct 22, 2004
    #7
  8. I don't personally find the interface case any more confusing than the
    class case. YMMV.


    John Bollinger
     
    John C. Bollinger, Oct 22, 2004
    #8
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.