Search code examples
javapolymorphismoverloadingfactory-pattern

Can you automatically cast an object of one class to a subclass and call an overloaded method in Java?


I have the following setup:

class Base {};
class ImplA extends Base {};
class ImplB extends Base {};
class ImplC extends Base {};

Base baseFactory(int type) {
    switch(type) {
    case 0:
        return new ImplA();
    case 1:
        return new ImplB();
    case 2:
        return new ImplC();
}

Base a = baseFactory(0);
Base b = baseFactory(1);
Base c = baseFactory(2);


List<Base> list = new ArrayList<Base>();

list.add(a);
list.add(b);
list.add(c);

// Somewhere else I have:
interface BaseHandler {
    process(ImplA a);
    process(ImplB b);
    process(ImplC c);
};

Now, what I would like to be able to do is something along the lines of:

class Processor {

BaseHandler bh;

Processor(BaseHandler bh) {
    this.bh = b;
}

void processList(List<Base> list) {

    for (Base x : list) {
        bh.process(x);
    }
}

And then have a user implement BaseHandler and be able to construct a Processor to operate on each element in the Base list.

But, this does not work as process(Base) is not defined. It may seem simple to just add 3 if statements, but I already have a switch like structure in building instances of classes extending the Base. It seems unnecessary to repeat this over and over. Is there a way to achieve this idea without writing an intermediate step that determines the runtime class of each Base in the list and calls the appropriate method (in effect another switch case -- but it would be if's)?

I think one work around idea would be to make each Base have an abstract process method which needs to be implemented by the Impl classes. However, this is not acceptable in my situation since the user will not be implementing the Impl classes. Basically, I need process to be a user-defined callback. Further, it does not make sense for process to be a member of the Impl or Base classes since it is in no way related. It's a separate callback that needs to respond dynamically to the type it is called with. And the type is always guaranteed to be a subclass of Base.


Solution

  • You do need the "intermediate step" that you describe, but it need not be if statements. What you're looking for is double dispatch using the visitor pattern. Basically your Base class would have a method:

    void accept(BaseHandler handler);
    

    and each subclass would implement it as:

    handler.process(this);
    

    where this would resolve to the correct type in each subclass at compile-time.