Question

I need to fire different methods depending on the value of parent and child which are different values of the same enum type. Currently I do this:

switch (parent)
{
  case DEPARTMENT:
  {
    switch (child)
    {
      case TERMINAL:
      {
        event1();
        break;
      }
      case OPERATOR:
      {
        event2();
        break;
      }
    }
    break;
  }
  case OPERATOR:
  {
    switch (child)
    {
      case TERMINAL:
      {
        event3();
        break;
      }
    }
    break;
  }
}

The actual code contains 5-10 cases, with each case executing one or more long lines of code (methods with multiple arguments).

I tried populating a two-dimensional array with Runnables but it executed 2x slower.

Is there an alternative way of writing this, which would be more readable, yet nearly as fast?

Était-ce utile?

La solution

An integer selector calculated from the combined values of parent and child will be faster:

public enum Stuff { DEPARTMENT, OPERATOR, TERMINAL };
Stuff parent = ...;
Stuff child  = ...;

int selector = parent.ordinal() * Stuff.values().length + child.ordinal();
switch(selector)
{
    case 0 : // parent=DEPARTMENT child=DEPARTMENT
        ...
    case 1 : // parent=DEPARTMENT child=OPERATOR
        ...
        ...
    case 3 : // parent=OPERATOR child=DEPARTMENT
        ...
    case 8:  // parent=TERMINAL child=TERMINAL
        ...
}

Some combinations may not be meaningful, just omit them and provide a default with nothing in it. You could also define constants in the enum:

private static final int n = values().length; // for brevity
public static final int DEPARTMENT_DEPARTMENT = DEPARTMENT.ordinal() * n + DEPARTMENT.ordinal()
        ...

and use those in the case statements.

Autres conseils

class SwitchTable {
    private static class EventKey {
        private EnumType parent;
        private EnumType child;
        public EventKey (EnumType p, EnumType c) { parent=p; child=c; }
        public int HashCode () { ...something... }
    } 
    private HashMap<EventKey, Integer> events;
    public void setEvent (EnumType parent, EnumType child, int eventNumber) {
         ... add a map entry to events that maps new EventKey(parent,child) 
         ... to eventNumber
    }
    public int whichEvent (EnumType parent, EnumType child) {
         ... return the map entry for new EventKey(parent,child) or 0 if not found
    }
}

// do this once to set up
SwitchTable switches = new SwitchTable();
switches.setEvent (EnumType.DEPARTMENT, EnumType.TERMINAL, 1);
switches.setEvent (EnumType.DEPARTMENT, EnumType.OPERATOR, 2);
switches.setEvent (EnumType.OPERATOR, EnumType.TERMINAL, 3);

// then
switch (switches.whichEvent(parent, child)) {
    case 1:  event1();  break;
    case 2:  event2();  break;
    case 3:  event3();  break;
}

I'm too lazy to fill in all the details, but you get the idea. This should work even if the parent and child are different enum types. You could use a different implementation for SwitchTable (e.g. set up a 1- or 2-dimensional array to hold the event values instead of a HashMap). I haven't tested this and don't know how it compares speed-wise. I hope I didn't make any dumb syntax errors.

EDIT: whichEvent doesn't have to return an integer. You could make it a new enum type whose names reflect the kinds of actions you might want to take. That should improve readability.

Most of the cases, to archive readability compromises performance. Here is a solution works ONLY with java7.

public class SwitchArray {

    public enum Stuff {
        DEPARTMENT, OPERATOR, TERMINAL
    };

    static Stuff parent = Stuff.DEPARTMENT;
    static Stuff child = Stuff.OPERATOR;

    /**
     * @param args
     */
    public static void main(String[] args) {
        switch (SwitchArray.parent.toString() + "_" + SwitchArray.child.toString()) {
        case "DEPARTMENT_OPERATOR":
            System.out.println("hey!");
            break;
        case "DEPARTMENT_TERMINAL":
            System.out.println("ha!");
            break;
        default:
            break;
        }
    }

}

Add a method to your enum (I'm calling it a MyEnum)

public void doFireEvent(MyEnum child) { // a single switch here for each enum }

Slightly cleaner IMO, at least it moves all that code to the enum class so you won't see it. :-)

(added later). A drawback of this is that your MyEnum class must have knowledge of / access to the event1() etc. methods, which may be impossible or inappropriate.

Your code can be made much more readable just by using better indentation and formatting techniques and also encapsulating all this dirty logic within the enum itself. It s really your formatting more than anything that makes it so difficult to trace.

public enum MyEnum {

    OPERATOR, TERMINAL;

    public static void execute(MyEnum parent, MyEnum child) {
        switch(parent) {
            case OPERATOR:
                switch(child) {
                    case OPERATOR: event1(); break;
                    case TERMINAL: event2(); break;
                }
            break;
            case TERMINAL:
                switch(child) {
                    case TERMINAL: event3(); break;
                }
            break;
        }
    }

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top