jeudi 10 mars 2016

Avoiding instanceof when polymorphism can't be used

I have multiple classes generated from XSD files using XJC. These classes are automatically generated as part of the build process and therefore can't be modified. The classes share a common structure. I have client code that needs to use these classes. However, some of this client logic is the same for all the classes. Therefore, I don't want to duplicate the client code for every class to support. The popular solution that comes to mind in such case is to use interface/inheritance so that client code only deals with super class/interface instead of the specific classes. However, in this case, this solution is not possible since the classes can't be modified. Therefore, I guess the right direction is to use composition instead of inheritance. However, if composition is used, the composing class will need to deal with every specific classes so I will probably end up with many if (obj instanceof Type) to handle every case separately.

public class A {
    private int id;
    //Properties specific to type A
}

public class B {
    private int id;
    //Properties specific to type B
}

public class C {
    private int id;
    //Properties specific to type C
}

public class Client {
    public void myMethod(Object obj) {
        //obj may be an instance of A, B or C

        //I would like to access the id property (which is common to A, B and C)
        //using the most elegant way

        //Approach using instanceof
        if(obj instanceof A) {
            A objA = (A)obj;
            objA.getId();
        }
        if(obj instanceof B) {
            B objB = (B)obj;
            objB.getId();
        }
        if(obj instanceof C) {
            C objC = (C)obj;
            objC.getId();
        }
    }
}

I thought about using an approach where the instance is wrapped and the instanceof logic is inside the wrapper class instead of the client code.

public class Wrapper {
    private Object obj;

    public int getId() {
        if(obj instanceof A)
            return ((A)obj).getId();
        if(obj instanceof B)
            return ((B)obj).getId();
        if(obj instanceof C)
            return ((C)obj).getId();
    }
}

public class Client {
    public void myMethod(Wrapper wrapper) {
        //Only deals with wrappers, not with the objects themselves

        wrapper.getId();
    }
}

Is the use of instanceof necessary in this case? If yes, what is the recommended approach?


EDIT:

Reflection can also be used to avoid the multiple instanceof. Following the given example, if the getId() method is defined in every class (A, B and C), the following is possible:

public class Wrapper {
    private Object obj;

    public int getId() {
        return obj.getClass().getMethod("getId").invoke(obj);
    }
}

Aucun commentaire:

Enregistrer un commentaire