Somu
Somu

Reputation: 3750

Relating enums and using in generics

I need to create enums for countries and states.

  1. What's the most appropriate way to create and relate these enums (as in country X can have states P, Q, R and so on)?

  2. If I have a generic class parameterized with a Country type, can I declare a method which will accept a State only available to the specific country?

For example something like:

public abstract class TestClass <T extends Country> {
    public void addState(T.State state);
    public List<T.State> getSelectedStates();
}

Edit 1: For easier maintenance, I would prefer to have a separate State enum for each Country as opposed to a single State enum with hundreds of states of all countries. Please comment.

Edit 2: I used the following solution for a problem very similar to this.

Solution: As @Bohemian suggested,

interface Country { }
interface State<T extends Country> { }

public class Countries {
    public static class USA implements Country { }
    public static class India implements Country { }
}

enum UsaStateEnum implements State<Countries.USA> {
    NY, MA, MD, CA
}

enum IndiaStateEnum implements State<Countries.India> {
    DEL, BLR
}

class GenericClass<T extends Country> {

    List<State<T>> states;

    public void addState(State<T> state) {
        if (states == null) {
            states = new ArrayList<State<T>>();
        }
        states.add(state);
    }

    public List<State<T>> getSelectedStates() {
        return states;
    }
}

public class NestedEnumTest {
    public static void main(String[] args) {
        GenericClass<Countries.USA> obj = new GenericClass<Countries.USA>();
        obj.addState(UsaStateEnum.MA);
        // obj.addState(IndiaStateEnum.DEL); // NOT ALLOWED

        List<State<Countries.USA>> states = obj.getSelectedStates();
    }
}

Upvotes: 1

Views: 464

Answers (2)

Bohemian
Bohemian

Reputation: 425033

To answer part 1, you can define two enums, one of which references the other, like this:

public enum State {
    A, B, C, D, E
}

public enum Country {
    USA(State.A, State.B),
    UK(State.C, State.D);

    private final List<State> states;

    Country(State... states) {
        this.states = Arrays.asList(states);
    }

    public List<State> getStates() {
        return states;
    }
}

To answer part 2, "no" - there is no way to restrict instances of a particular class to a subset.

You could if you defined a separate class for each country and a separate enum for the states it has, but this doesn't seem like a good idea.

Upvotes: 1

Adam Arold
Adam Arold

Reputation: 30528

You can make an enum implement an interface like this:

public enum MyEnum implements MyInterface<MyType> {
    // ...
}

Apart from implementing interfaces enums do not support inheritance yet but if you wish to have common functionality in your enums you can always compose for example some strategy object into them.

Upvotes: 1

Related Questions