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

发布于 2024-10-02 08:04:37 字数 564 浏览 2 评论 0原文

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

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 语句。

这样的需求有什么模式吗?

谢谢

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

南冥有猫 2024-10-09 08:04:37

尽管我不确定它会好得多,但您可以做的是两个状态值的所有可能组合的某种矩阵;然后,您可以使用 o1.state 和 o2.state 作为该矩阵的索引。

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

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

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

如果你真的想摆脱if 语句,第二个选项可能是更好的一个;但请注意,您的代码将不再像 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);
}

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

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);
}
叹沉浮 2024-10-09 08:04:37

构建此结构的一种方法是,您可以在枚举中拥有一个抽象方法,每个元素都将实现该方法:

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

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);
}
爱的故事 2024-10-09 08:04:37

是的,它被称为...状态模式。重要的是只有一个状态可以定义行为,即您可能需要将 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

然后,您需要在状态上下文中保存一个 MyObjectStates 对象,并在 MyObject.state 更改时更新它。您甚至可以完全删除状态枚举。如果您对这种方法感兴趣,请给我留言,如果您愿意,我会详细说明。

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

Yes, it is called the... state pattern. The important thing is to only have one state for which to define behavior, i.e. 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.

一生独一 2024-10-09 08:04:37

我可能已经这样做了,它至少更具可读性

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

                    break;
                }
                case B: {

                    break;
                }

            }
            break;
        }
    }
}

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;
        }
    }
}
柠檬 2024-10-09 08:04:37

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

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

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

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

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

童话 2024-10-09 08:04:37

面向对象的问题解决方案是状态模式。它涉及用状态对象封装状态交替条件。您可以在此处此处。顺便说一句,如果您还没有这本书,我强烈建议您购买它。

干杯!

The OO solution to your problem is the state pattern. 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!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文