views:

580

answers:

8

Hello,

I have an object tree that looks something like

           Ball
          /    \
  LegalBall    IllegalBall

And I have 2 methods:

class o {
AddBall(LegalBall l)
AddBall(IllegalBall i)
}

in another class I'd like to do the following:

o.AddBall(myBall);

where myBall is of type Ball. And get it to call the correct method depending on the subtype. Apparently I can't do this... the arguments are not applicable.

Does anyone know how I can achieve what I want? Or if there is a good work around

Thanks

EDIT : the application I'm trying to build is a Cricket scorecard type thing. So depending on the type of ball that is bowled various other elements should change.

my original intention was to be able to specify the ball type and runs scored from some form of UI and then create an appropriate type ball from a BallFactory and then for example when I send a no ball to the team score it will add the value onto the team score but also add the value to the no balls counter. But when i give the same ball to the Batsmens Analysis to deal with it should only score value-1 to the batsmens total..

I hope thats not too bad an explanation of my original intention.

A: 

How do you expect it to know which one to call? What sets the two methods apart that you would expect it to call one and not the other?

Joel Coehoorn
+1  A: 

You should try to implement only one method:

class o {
AddBall(Ball b)
}

and try to rely on polymorphism for different behavior with respect to different classes. Of course the details depend on the implementation of the Ball hierarchy.

Federico Ramponi
A: 

You might (or might not) want (part of) the visitor pattern.

Add a method to Ball:

public abstract void addTo(o o);

Implementat in LegalBall and IllegalBall as

public void addTo(o o) {
    o.add(this);
}
Tom Hawtin - tackline
+3  A: 

You could use the Vistor pattern.

class Basket {
    void AddBall(LegalBall l) {
        System.out.println("LegalBall added to basket");
    }

    void AddBall(IllegalBall i) {
        System.out.println("IllegalBall added to basket");
    }
}

interface Ball {
    void AddBall(Basket b);
}

class LegalBall implements Ball {
    void AddBall(Basket b) {
        b.AddBall(this);
    }
}

class IllegalBall implements Ball {
    void AddBall(Basket b) {
        b.AddBall(this);
    }
}

or to make it more general:

interface BallVisitor {
    void visit(LegalBall l);
    void visit(IllegalBall i);
}

interface Ball {
    void accept(BallVisitor v);
}

class LegalBall implements Ball {
    void accept(BallVisitor v) {
        v.visit(this);
    }
}

class IllegalBall implements Ball {
    void accept(BallVisitor v) {
        v.visit(this);
    }
}

class Basket implements BallVisitor {
    void visit(LegalBall l) {
        System.out.println("LegalBall added to basket");
    }

    void visit(IllegalBall i) {
        System.out.println("IllegalBall added to basket");
    }
}
dalle
I will need to AddBall to more than just Basket though, a number of other objects. Will I need to implement a method for each type I want to add ball to?
Rocco
Updated with general case.
dalle
It would be jolly odd to add "visit" and "accept" methods to an otherwise normal interface.
Tom Hawtin - tackline
A: 

Well there's the visitor pattern, as mentioned above. If you can't or don't want to modify Ball, LegalBall, or IllegalBall, then you might try having a single method branch based on on the type of ball. Note that if you later add a QuasiLegalBall, this code will break. The general case that you mention is difficult because the existence of LegalBall and IllegalBall doesn't prevent there being Balls that don't fit into the two types you described (from the language's perspective, at least).

class o {
    public void AddBall(Ball b) 
    { 
        if (b instanceof LegalBall) {AddLegalBall(b); }
        else if (b instanceof IllegalBall) {AddIllegalBall(b); }
        else { /*error, new type of ball created*/ }
    }
    private void AddLegalBall(LegalBall b) { }
    private void AddIllegalBall(IllegalBall b) { }
    }
 }
Yuliy
A: 

I agree with the Visitor usage.

Additionally if you don't have access to the Ball hierarchy ( source code access ) or simple don't feel like modifying anything there; you could modify your client class and decide from there.

The bad thing of course is you'll end up with many if/elseif statements.

You'll need to add the generic method ( add( Ball ) ) and from there call the others. This is quick, easy and dirty.

:)

public class Test {
    public static void main( String [] args ) { 
        Ball ball = new IllegalBall();
        Test test = new Test();
        test.add( ball );
        test.add( new IllegalBall() );
        test.add( new LegalBall() );
    }
    private void add( Ball ball ){
        System.out.println("Generic method: I'll have someone handling this : "  + ball );
        if( ball instanceof IllegalBall ) {
            add( ( IllegalBall ) ball );
        } else if( ball instanceof LegalBall ) {
            add( ( LegalBall ) ball );
        }
    }
    private void add( IllegalBall ball ){
        System.out.println("illega-ball: I won't do anything about it! " + ball );
    }
    private void add( LegalBall ball ) { 
        System.out.println("legal-ball: Hey this is legal I'll do my best!! " + ball );
    }
}

class Ball {}
class IllegalBall extends Ball {}
class LegalBall extends Ball {}

BTW if you don't have the reference directly the compiler will send it to the correct method as in the last 2 calls.

As you can see you just need to add the following code:

private void add( Ball ball ){
    System.out.println("Generic method: I'll have someone handling this : "  + ball );
    if( ball instanceof IllegalBall ) {
        add( ( IllegalBall ) ball );
    } else if( ball instanceof LegalBall ) {
        add( ( LegalBall ) ball );
    }
}
OscarRyz
Horrible. This is a textbook example of how "instanceof" and method overloading are code smells for a bad design. You are abusing the type system.
eljenso
A: 

The Visitor pattern, and similar solutions using callbacks, in this case only seem to try to bend your code in such a way to get the compiler to accept your flawed class hierarchy.

I would keep type Ball, and make legal/illegal a property of that type. You would only have o.add(Ball), in which you check for legal/illegal based on some properties or through a method, isLegal() for example.

If the above approach does not seem reasonable, then it is not reasonable to have a single method to add two (very) distinct types, and the subtyping relationship you proposed would not be the way to go.

eljenso
A: 

Use the visitor pattern. Doing it without is cumbersome, and was subject of this question: http://stackoverflow.com/questions/370812/work-around-javas-static-method-dispatching-without-double-dispatchvisitor-patt .

However, can you please state your original problem? I mean, why do you need to have those two overloads for the Add method? Maybe you can solve it in a completely different way which doesn't need to rely on dynamic dispatch like the visitor pattern?

Johannes Schaub - litb