简体   繁体   English

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

[英]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: 我需要编写一个算法,该算法需要两个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...

}

Obviously this approach has many problems and I would like to change it to ideally get rid of the if/else statement. 显然这种方法有很多问题,我想改变它,以理想地摆脱if / else语句。

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; 可以做什么,虽然我不确定它会好得多,但它是两种state值的所有可能组合的某种矩阵; you could then use o1.state and o2.state as indexes into that matrix. 然后你可以使用o1.stateo2.state作为该矩阵的索引。

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. 一个唯一的值,您可以将其用作switch块的区分值,它将替换您的if .. else if .. else块 - 实际上并没有太大的改进。

Or your matrix could contain... 或者你的矩阵可以包含......

If you really want to get rid of the if statements, that second option might be the better one; 如果你真的想摆脱if语句,那么第二种选择可能是更好的选择; 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. 但请注意,您的代码将不再在一个位置靠近,如if / switch块的情况,但会分布在几个不同的命令对象/类中。

// 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. 重要的是只有一个状态可以定义行为,即您可能需要将object1.state和object2.state组合成一个元状态。 Register this meta-state with a statecontext so that when Myobject.state changes the meta-state is updated. 使用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

You then need to hold one MyObjectStates object in a statecontext and update it when a MyObject.state is changed. 然后,您需要在statecontext中保存一个MyObjectStates对象,并在更改MyObject.state时更新它。 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. 状态模式的优点是您不需要保存和读回枚举并相应地选择不同的代码路径,而是为每个要以不同方式处理的状态提供单独的代码。

I 'd done this probably , its at least more readable 我可能做到了这一点,它至少更具可读性

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

                    break;
                }
                case B: {

                    break;
                }

            }
            break;
        }
    }
}

using only two state combinations, a nested switch is probably the quickest to implement and comprehend: 只使用两种状态组合,嵌套开关可能是最快实现和理解的:

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

If the case order is irrelevant for certain combinations, you may be able to swap o1 and o2 in those cases, then drop them into the switch (and avoid duplicate code). 如果案例顺序与某些组合无关,则可以在这些情况下交换o1o2 ,然后将它们放入switch (并避免重复代码)。 Also, for all the cases combinations that have the same behavior, you can take advantage of the fall through behavior. 此外,对于具有相同行为的所有情况组合,您可以利用跌倒行为。

Finally, implementing it this way may make what's actually going on with those combinations a little more obvious, such that you might be able to implement a much smarter approach. 最后,以这种方式实现它可能会使这些组合的实际情况变得更加明显,这样您就可以实现更智能的方法。

The OO solution to your problem is the state pattern. 问题的OO解决方案是状态模式。 It involves encapsulating state-alternating conditionals with a state object. 它涉及使用状态对象封装状态交替条件。 You may find more information about the pattern here and here . 您可以在此处此处找到有关模式的更多信息。 By the way, i would STRONGLY suggest buying this book if you don't already own it. 顺便说一下,如果您还没有购买本书,我强烈建议购买。

Cheers! 干杯!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM