Refactor if statement to use appropriate pattern

I have an enum with some states in it:

enum State
{
    A,
    B,
    C,
    D
}

and an object that has a corresponding state:

class MyObject
{
    State state;
}

I need to write an algorithm that takes two MyObject instances and does something depending on the particular states of those instances:

void doWork(MyObject o1, MyObject o2)
{
     if (o1.state == A && o2.state == A)
     {
          // do something
     }
     else if (o1.state == A && o2.state == B)
     {}
     // etc for all combinations...

}

Obviously this approach has many problems and I would like to change it to ideally get rid of the if/else statement.

Is there any pattern for such a requirement?

Thanks


What you could do, although I'm not sure it would be that much better, is some kind of matrix of all possible combinations of two state values; you could then use o1.state and o2.state as indexes into that matrix.

You could store different things in that matrix:

  • a unique value that you can use as the discriminating value for a switch block which would replace your if .. else if .. else blocks -- not much of an improvement, really.
  • Or your matrix could contain...

  • command objects. (Look up the Command Pattern.)
  • If you really want to get rid of the if statements, that second option might be the better one; do take note, however, that your code will then no longer be close together in one location, as would be the case with if / switch blocks, but spread over several different command objects/classes.

    // forgive my syntax errors etc., my Java has definitely gone a little rusty!
    
    interface WorkCommand {
        public abstract void run(MyObject o1, MyObject o2);
    }
    
    ...
    
    Map<Pair<State,State>, WorkCommand> commands;
    // ^ pseudo-code type for your command look-up map; type Pair<X,Y> doesn't exist,
    //   so replace this with something sensible!
    
    void doWork(MyObject o1, MyObject o2)
    {
        WorkCommand worker = commands.get(new Pair<State,State>(o1, o2));
        worker.run(o1, o2);
    }
    

    One way you can structure this, is you can have an abstract method in your enum which each element would implement:

    enum State
    {
        A{
          public void void doSomeWork(State state){
            switch(state){
               case A:
               case B:
               ...
            }
          }
        },
        B,
        C,
        D
    
        abstract void doSomeWork(State state);
    }
    

    Then your method can look like

    void doWork(MyObject o1, MyObject o2){
       o1.state.doSomeWork(o2.state);
    }
    

    Yes, it is called the... state pattern. The important thing is to only have one state for which to define behavior, ie you may need to combine your object1.state and object2.state into a meta-state. Register this meta-state with a statecontext so that when Myobject.state changes the meta-state is updated.

    interface MyObjectStates {
      void doWork(MyObject o1, MyObject o2);
    }
    
    class MyObjectStatesAA implements MyObjectStates {
      void doWork(MyObject o1, MyObject o2) {
        // do dowork for both states A
      }
    
    class MyObjectStatesBB implements MyObjectStates {
      void doWork(MyObject o1, MyObject o2) {
        // do dowork for both states B
      }
    
    // etc
    

    You then need to hold one MyObjectStates object in a statecontext and update it when a MyObject.state is changed. You may even be able to remove the state enum alltogether. If this approach sounds interesting to you give me a note and I elaborate if you like.

    The state pattern has the advantage that you don't need to save and read back an enum and chose a different codepath accordingly, but instead you provide separate code with every state you want to handle differently.

    链接地址: http://www.djcxy.com/p/91844.html

    上一篇: 如何在if条件中避免NullPointerException

    下一篇: 重构if语句以使用适当的模式