user1583209
user1583209

Reputation: 1707

Java refactoring interlinked switch/if statement with polymorphism

I am aware of how to replace a switch statement through polymorphism, like it is explained for instance here.

In my case however I have two Enum:

public enum EleType {
    INTEGER, 
    CHARACTER
}

and

public enum SorterType {
    BUBBLE,
    INSERTION
}

and the switch/if I would like to refactor has the structure:

if ( eleType == EleType.INTEGER ) {
    switch ( sorterType ) {
        case BUBBLE:
             composition = new SorterComposition<Integer>(new BubbleSort<Integer>(), randomList);
             break;
        case INSERTION:
             composition = new SorterComposition<Integer>(new InsertionSort<Integer>(), randomList);
             break;
    }
} else if ( eleType == EleType.CHARACTER ) {
    switch ( sorterType ) {
        case BUBBLE:
             composition = new SorterComposition<Character>(new BubbleSort<Character>(), randomList);
             break;
        case INSERTION:
             composition = new SorterComposition<Character>(new InsertionSort<Character>(), randomList);
             break;
    }
}

Because both enum appear together and both affect the SorterComposition part, I am unsure how to refactor this structure. Also I am unsure how to get the "Integer"/"Character" generic types from EleType.INTEGER or EleType.CHARACTER respectively without using conditional statements.

Upvotes: 1

Views: 490

Answers (2)

Aaron
Aaron

Reputation: 881

You could use double dispatch. I have provided a skeleton implementation below. However some consider double dispatch a code smell. In this instance your EleType seems suspect to me. All you are doing with it in this example is use it for your generic type declaration.

    public enum EleType {
    INTEGER {
        SorterComposition getSorter(SorterType s) {
            return s.getIntegerSorter();
        }
    }, 
    CHARACTER{
        SorterComposition getSorter(SorterType s) {
            return s.getChracterSorter();
        }

    };

    abstract SorterComposition getSorter(SorterType s);
};

public enum SorterType {
    BUBBLE {
        SorterComposition getIntegerSorter() {return new BubbleSort<Integer>();}
        SorterComposition getChracterSorter() {return new BubbleSort<Character>();}
    },
    INSERTION{
        SorterComposition getIntegerSorter() {return new InsertionSort<Integer>();}
        SorterComposition getChracterSorter() {return new InsertionSort<Character>();}
    };

    abstract SorterComposition getIntegerSorter();
    abstract SorterComposition getChracterSorter();

};

Upvotes: 0

EmOwen
EmOwen

Reputation: 104

Do you mean that you implement the code like this?

public static <T> SorterComposition<T> createComposition(SorterType type, <Type of randomList>) {
    switch (type) {
        case BUBBLE:
            return new SorterComposition<T>(new BubbleSort<T>(), randomList);
        case INSERTION:
            return new SorterComposition<T>(new InsertionSort<T>(), randomList);
        default:
            throw <Exception>
    }
}

Or, you can change the EleType class a little bit.

public enum EleType {
    INTEGER(Integer.class), CHARACTER(Character.class);
    private EleType(Class cl) { this.classType = cl; }
    public Class getClassType() { return classType; }
    private final Class classType;
}

and use this code instead of the createComposition above.

public static <T> SorterComposition<T> createComposition(Class<T> eleType, SorterType type, <Type of randomList>) {
    switch (type) {
        case BUBBLE:
            return new SorterComposition<T>(new BubbleSort<T>(), randomList);
        case INSERTION:
            return new SorterComposition<T>(new InsertionSort<T>(), randomList);
        default:
            throw <Exception>
    }
}

and when you use it, use composition = createComposition(eleType.getClassType(), sorterType, randomList);


To avoid switch of SorterType in a gentle way, maybe you can use in add a Supplier field into SorterType.

public enum SorterType {
    BUBBLE(() -> new BubbleSort()),
    INSERTION(() -> new InsertionSort());

    private SorterType(Supplier<Sort> supplier) {
        this.supplier = supplier;
    }

    public Sort getSort() {
        return supplier.get();
    }

    private final Supplier<Sort> supplier;
}

Upvotes: 1

Related Questions