Search code examples
refactoringswitch-statementabstract-classinstanceof

How to avoid casting and instanceOf


I got a method that does the following:

private void computeHierarchie(GlobalKey key) {
    HierarchieValue hierarchieValue = hierarchieFactory.createHierarchie(selectedKey);
    ....
}

GlobalKey has 4 childs: KeyA, KeyB, KeyC and KeyD.

At the moment my factory looks like the following:

public class HierarchieFactory {

    // inject someFacade which has 4 different methods

    public HierarchieValue createHierarchie(GlobalKey key) {
        if (key instanceof KeyA) {
            return someFacade.computeHierarchie((KeyA) key);
        }
        if (key instanceof KeyB) {
            return someFacade.computeHierarchie((KeyB) key);
        }
        if (key instanceof KeyC) {
            return someFacade.computeHierarchie((KeyC) key);
        }
        if (key instanceof KeyD) {
            return someFacade.computeHierarchie((KeyD) key);
        }
        return new HierarchieValue();
    }

}

I really don't like this switch-case thing, but to be honest, I can't compute any worthy refactoring. I tried something like the following:

public abstract class AbstractHierarchieFactory {

    //inject someFacade

    abstract <T extends GlobalKey> HierarchieValue createHierarchie(T key);

}

And then the 4 classes extending this one. One would look like:

public class KonzernHierarchieFactory extends AbstractHierarchieFactory {

    @Override
    HierarchieValue createHierarchie(KonzernKey konzernKey) {
        return evaFacade.computeHierarchie(konzernKey);
    }

}

This would be so nice! But sadly this doens't work. Do you have any other suggestions? There must be a standard way to solve this problem.


Solution

  • This seems like a prime example for a Visitor pattern.

    e.g. let's say you have a KeyVisitor interface with the methods visitA(KeyA key), …, visitD(KeyD key). Then you can code the a method into your Key classes (which must obviously also available from a common base class):

    void visit(KeyVisitor visitor) { visitor.visitX(this); }

    Where you replace the X with your A..D, depending on class. Now your factory can implement KeyVisitor and handle your key classes separately.