重构if语句以使用适当的模式

时间:2010-11-12 19:23:28

标签: java oop design-patterns

我有一个包含一些状态的枚举:

enum State
{
    A,
    B,
    C,
    D
}

和具有相应状态的对象:

class MyObject
{
    State state;
}

我需要编写一个算法,该算法需要两个MyObject实例,并根据这些实例的特定状态执行某些操作:

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...

}

显然这种方法存在很多问题,我想改变它以理想地摆脱if / else语句。

这种要求是否有任何模式?

由于

6 个答案:

答案 0 :(得分:3)

可以做什么,虽然我不确定它会好得多,但它是两种state值的所有可能组合的某种矩阵;然后,您可以使用o1.stateo2.state作为该矩阵的索引。

您可以在该矩阵中存储不同的内容:

  • 一个唯一值,您可以将其用作替换switch块的if .. else if .. else块的区分值 - 实际上并没有太大的改进。

或者你的矩阵可以包含......

如果你真的想摆脱if陈述,第二种选择可能是更好的选择;但请注意,您的代码将不再在一个位置靠近,就像if / switch块一样,但会分布在几个不同的命令对象/类中。 / p>

// 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);
}

答案 1 :(得分:2)

您可以构建此方法的一种方法是,您可以在枚举中使用每个元素实现的抽象方法:

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

    abstract void doSomeWork(State state);
}

然后你的方法看起来像

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

答案 2 :(得分:2)

是的,它被称为...... state pattern。重要的是只有一个状态可以定义行为,即你可能需要将object1.state和object2.state组合成一个元状态。使用statecontext注册此元状态,以便在Myobject.state更改时更新元状态。

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

然后,您需要在statecontext中保存一个MyObjectStates对象,并在更改MyObject.state时更新它。您甚至可以完全删除状态枚举。如果这种方法听起来很有意思,请给我一个注释,如果你愿意,我会详细说明。

状态模式的优点是您不需要保存和读回枚举并相应地选择不同的代码路径,而是为每个要处理的状态提供单独的代码。

答案 3 :(得分:1)

我可能做到了这一点,至少更具可读性

void doWork(MyObject o1, MyObject o2) {
    switch (o1.state) {
        case A: {
            switch (o2.state) {
                case A: {

                    break;
                }
                case B: {

                    break;
                }

            }
            break;
        }
    }
}

答案 4 :(得分:0)

只使用两种状态组合,嵌套开关可能是最快实现和理解的:

switch (o1.state) {
 case X: switch(o2.state) { }
 //..etc
}

如果案例订单与某些组合无关,您可以在这些情况下交换o1o2,然后将其放入switch(并避免重复代码) 。此外,对于具有相同行为的所有情况组合,您可以利用跌倒行为。

最后,以这种方式实现它可能会使这些组合的实际情况变得更加明显,这样您就可以实现更智能的方法。

答案 5 :(得分:0)

问题的OO解决方案是状态模式。它涉及使用状态对象封装状态交替条件。您可以找到有关模式herehere的更多信息。顺便说一句,如果你还没有这本书,我强烈建议购买这本书。

干杯!