How to avoid instanceof

133 Views Asked by At

I have interface AAA. I have two classes (entities):

public class BBB implements AAA

public class CCC implements AAA

Both classes have different fields of course that will be used in Service

I have Service:

public class Service() {
    public DDD returnDdd(AAA aaa){
        ....
        return method1(aaa);
    }
    private DDD method1(AAA aaa){
        if(aaa instanceof BBB){
            return method2(aaa)
        }
        return method3(aaa)
    }
}

How to avoid instanceof? In my Service I have common logic for both BBB and CCC. Method1 and Method2 use the same private methods in this service.

2

There are 2 best solutions below

7
Dmitrii Karmanov On

In this case I would recommend to have a common method in the interface AAA, like:

public interface AAA {
    void method1();
}

and make both inherited classes to implement this method. In this case you will have to call only one method which will be automatically chosen based on the exact instance.

public class Service() {
    public void ddd(AAA aaa){
        aaa.method1();
    }
}

...

public class Main {
    public static void main(String[] args) {
        AAA b = new BBB();
        AAA c = new CCC();

        new Service().ddd(b); // b.method1() will be called
        new Service().ddd(c); // c.method1() will be called
    }
}
2
WJS On

Ok, this may be unorthodox but it works unless there is some other requirement that is missing from your code. I am not using interface AAA method for anything but can be added if required.

But I don't really see any problem using instanceof.

class Service {    
    public DDD returnDDD(AAA aaa) {
        return switch(aaa.getClass().getSimpleName()) {
            case "BBB" -> method2((BBB)aaa); // casting depends on method
                                             // signatures
            case "CCC" -> method3((CCC)aaa);
            default -> null; // or some appropriate return value.
        };
    }
    public DDD method2(BBB b) {
        System.out.println("Calling method2");
        return new DDD();
    }
    public DDD method3(CCC c) {
        System.out.println("Calling method3");
        return new DDD();
    }
}

prints

calling method2
calling method3

Here is how I would slightly modify your existing code. It casts AAA to the appropriate subtype so you can make use of each class' attributes. The enhanced instanceof helps with this.

class Service {
    public DDD returnDDD(AAA aaa){
        return method1(aaa);
    }
    private DDD method1(AAA aaa){
        if(aaa instanceof BBB bbb){ // bbb cast for you
            return method2(bbb);
        }
        return method3((CCC)aaa); // do it explicitly
    }
}

The above presumes that method2 and method3 can accept the subtypes as arguments based on the method signatures. Otherwise, they may need to be cast internally to the method to access subtype attributes.