【问题标题】:Alternative of if-else and switch statementsif-else 和 switch 语句的替代方案
【发布时间】:2014-05-22 02:23:21
【问题描述】:

我在 Java 中有以下代码:

public void doSomething(int i) {
    if (i == 12) {
        // order should be same
        up();
        left();
        stop();
    }
    if (i == 304) {
        // order should be same
        right();
        up();
        stop();
    }
    if (i == 962) {
        // order should be same
        down();
        left();
        up();
        stop();
    }
}
// similar code can be done using switch case statements.
// all the function can have any functionality and might not resemble to the name given to them.

现在,如果我被要求不要使用 if-else 和 switch case 语句,那该怎么办?代码可以用 Java 或 JavaScript 编写。

【问题讨论】:

  • 只是确定一下,您实际上可以使用 JS (this language)?如果是这样,那很容易。
  • 用类似'12'的方法创建一个对象,并在该方法中调用你的函数。
  • 为每个键使用字典,您将拥有函数列表作为值,并根据键选择列表中的函数并迭代列表并调用每个函数。
  • 我永远不会理解要求学生“做 X,但不使用 Y,显然是正确的方法,或 Z 是另一种有效但尴尬的解决方案”的教学原因
  • “在 Java 或 JavaScript 中”没有意义。它们是两种非常不同的语言,具有两个非常不同的域。为了回答您的问题,两种语言都提供了几种多路 if:if-then-elseif-else 和某种switch。您当前的实现是有缺陷的,因为它命中了 each if 测试,而不是在第一场比赛后退出。这可能就是教练的意思。

标签: java javascript conditional-statements


【解决方案1】:

如果你会使用 JavaScript,你可以使用带有函数的对象:

function doSomething(i) {
  var obj = {};

  obj[12] = function () {
    // order should be same
    up();
    left();
    stop();
  };
  obj[304] = function () {
    // order should be same
    right();
    up();
    stop();
  };
  obj[962] = function () {
    // order should be same
    down();
    left();
    up();
    stop();
  };

  // apparently we can't use any conditional statements
  try {
    obj[i]();
  } catch (e) {}
}

如果只允许使用 ifswitch 语句,请将所有 if 语句替换为逻辑 AND 运算符 (&&):

function doSomething(i) {
  (i == 12) && (
    // order should be same
    up(),
    left(),
    stop()
  );

  (i == 304) && (
    // order should be same
    right(),
    up(),
    stop()
  );

  (i == 962) && (
    // order should be same
    down(),
    left(),
    up(),
    stop()
  );
}

【讨论】:

  • 第二个是使用 if 语句,但第一个值得投票 ;-)
  • 如果 OP 甚至禁止使用条件语句,它将是不可接受的 :)
  • 只想指出,第二个建议仅适用于使用短路评估的语言:en.wikipedia.org/wiki/Short-circuit_evaluation 从我的头顶开始只有帕斯卡不使用它。
  • @Hoffmann,但是 OP 正在谈论 Java 和 JS,两者都短路了。
  • 代替try/catch,我个人认为这样更具可读性:obj[i] && obj[i]();
【解决方案2】:

您可以制作一个输入到操作的字典。在 Java 中,这将是一个Map<Integer, Runnable>,例如*:

map.put(12, () -> {
    up();
    left();
    stop();
});

然后,您可以获取相应的Runnable 并运行它:

Runnable action = map.get(i);
if (action != null) {
    action.run();
} else {
    // some default action
    // This is the "default" case in a switch, or the "else" in an if-else
}

if-else 不是绝对必要的,但如果没有它,如果 i 不是预期值,您将得到 NullPointerException — 即您放入地图的值之一。

这个想法在 JavaScript 中是相似的,但使用对象而不是 Maps,函数(可能是匿名的)而不是 Runnables,等等。


此代码适用于 Java 8。在 Java 7 及更低版本中,您可以:

map.put(12, new Runnable() {
    @Override
    public void run() {
        up();
        left();
        stop();
    }
});

【讨论】:

  • @Puru-- 这个想法同样适用于 Java 7。但是,是的,您需要创建一个匿名类而不是使用 lambda。
  • @sura 是的,但如果您确信 i 始终是预期值,则不需要这样做。 (如果你错了,你会在action.run() 得到一个NullPointerException。)
  • @yshavit,我想你可以try...catch NPE 而不是用if...else 创建一个空保护。 :)
  • @BrianS 你可以,但这通常是个坏主意。如果 Runnable 本身有一个错误并抛出一个 NPE,你永远不会知道,因为那个 catch-and-ignore。最好让它传播出去,这样一些东西就可以对你大喊大叫。
  • 谁说你必须忽略异常? (并不是我认为 try/catch 是 if/else 的 good 替代品,只是在这种情况下它可以,并且符合 OP 的要求。)
【解决方案3】:

看,自然你应该用条件表达式检查条件语句! 现在,如果你不想这样做,你可以像这样不自然地这样做:

首先对所有方法(向上、向下、...)执行此操作

java.lang.reflect.Method method;
try {
  method = obj.getClass().getMethod(methodName, param1.class, param2.class, ..);
} catch (SecurityException e) {
  // ...
} catch (NoSuchMethodException e) {
  // ...
}

不要使用整数传递给doSomething,而是使用包含要调用的方法名称的数组,并在 for 循环中以这种方式调用每个方法:

然后你通过调用来调用该方法

try {
  method.invoke(obj, arg1, arg2,...);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {

很遗憾,Java 没有委托

【讨论】:

  • 虽然我相信这种方法会工作(因为它会产生预期的结果),但反射是解决这个问题的一个不必要的复杂解决方案,IMO。
  • @BrianS- 实际上,正如我已经说过的,在 java 中最自然的方法是使用 if 语句,但是由于 OP 不想要它,我尝试尽可能接近 c#代表,这是java中缺少的。
  • 常见的 Java 解决方案是观察者模式的一些变体(yshavit 的回答是简化版本)。不过,我承认,几年前我 wrote a class 以可重用的方式实现您的解决方案。
【解决方案4】:

对于 js 你可以试试这个:

// define ur actions here
var actions = {
  "12" : function () { up(); left(); stop(); },
  "304" : function () { right(); up(); stop(); },
  "962" : function () { down(); left(); up(); stop(); }
};

function doSomething(i) {
  var fn = actions[i];
  try {
    fn();
  } catch (err) {
    console.error(err);
  }
}
//
doSomething(12); //invoke here

【讨论】:

  • 写得非常巧妙。
【解决方案5】:

这是在 JavaScript 中完成此操作的简单方法:

function up()    { console.log("up");    }
function down()  { console.log("down");  }
function left()  { console.log("left");  }
function right() { console.log("right"); }
function stop()  { console.log("stop");  }

var fnmaps = {
    12:  [up, left, stop],
    304: [right, up, stop],
    962: [down, left, up, stop]
};

function doSomething(i) {
    var fnmap = fnmaps[i] || [], j;
    for (j = 0; j < fnmap.length; j++) {
        fnmap[j]();
    }
}

doSomething(12);
doSomething(304);
doSomething(962);

只需编辑地图变量即可添加/排序功能。

【讨论】:

    【解决方案6】:

    那就用while和break吧,没有条件检查就没有办法了

    public void doSomething(int i) {
    
    while(i == 12) {
    // order should be same
        up();
        left();
        stop();
    break;
        }
    
    while(i == 304) {
    // order should be same
        right();
        up();
        stop();
    break;
        }
    
    while(i == 962) {
    // order should be same
        down();
        left();
        up();
        stop();
    break;
        }
    }
    

    【讨论】:

    • 替代,同样糟糕:(i == 12 && (up (), left (), stop ())); (i == 304 && (右(), 上(), 停止())); (i == 962 && (下(), 左(), 上(), 停()));
    【解决方案7】:

    在 Java 中,这应该可以工作..

    public class IfTest {
    
        public static void main(String[] args) {
            IfTest ifTest = new IfTest();
    
            ifTest.doSomething(12);
            ifTest.doSomeThingWithoutIf(12);
    
            ifTest.doSomething(304);
            ifTest.doSomeThingWithoutIf(304);
    
            ifTest.doSomething(962);
            ifTest.doSomeThingWithoutIf(962);
    
            ifTest.doSomething(42);
            ifTest.doSomeThingWithoutIf(42);
        }
    
        public void doSomeThingWithoutIf(int i) {
    
    
            boolean x = i == 12 ? f12() : (i == 304 ? f304() : (i == 962 ? f962() : false));
        }
    
        public boolean f12() {
    
            up();
            left();
            stop();
    
            return true;
        }
    
        public boolean f304() {
    
            right();
            up();
            stop();
            return true;
        }
    
        public boolean f962() {
    
            down();
            left();
            up();
            stop();
    
            return true;
        }
    
        public void doSomething(int i) {
    
            if(i == 12) {
                // order should be same
                up();
                left();
                stop();
            }
    
            if(i == 304) {
                // order should be same
                right();
                up();
                stop();
            }
    
            if(i == 962) {
                // order should be same
                down();
                left();
                up();
                stop();
            }
        }
    
        private boolean retfalse() {
            return false;
        }
    
        private void down() {
            System.out.println("down");
        }
    
        private void right() {
            System.out.println("right");
        }
    
        private void stop() {
            System.out.println("stop");
        }
    
        private void left() {
            System.out.println("left");
        }
    
        private void up() {
            System.out.println("up");
        }
    }
    

    【讨论】:

    • 我会假设它是因为你用三元运算符做了 if-else。我认为 OP 想要一个没有 if-else 或同义词的解决方案。
    • 如果是这样的话,他肯定说过“不使用条件运算符”左右。我不擅长 JS,但是如果我查看为 Java 发布的解决方案,它们要么使用反射,要么使用 Map/Dictionary 等。对于这么简单的事情,我发现两者的性能和内存占用都很糟糕
    • 我不一定不同意你zencv。我只是提供了一个可能的原因来说明为什么它被否决了;)
    【解决方案8】:

    这个问题可以使用 OOP 技术来解决。

    在java中它看起来像这样:

    public abstract class AObject{
       public abstract  void doSomething();
       public void  up(){
          //do something here
       }
       public void down(){
          //do something here
       }
       public void left(){
          //do something here
       }
       public void right(){
          //do something here
       }       
       public void stop(){
          //do something here
       }     
    }
    
    
    public class AObject12 extends AObject{
       public void doSomething(){
          up();
          left();
          stop();
       }
    }
    
    public class AObject304 extends AObject{
       public void doSomething(){
          right();
          up();
          stop();
       }
    }
    
    public class AObject962 extends AObject{
       public void doSomething(){
          down();
          left();
          up();
          stop();
       }
    }
    

    在具体类的实例上执行 doSomething 将触发适当的行为。所以不再需要 if/else。示例见以下代码:

    AObject A12 = new AObject12();
    A12.doSomething();
    // Will run Up left stop in that order
    
    AObject A304 = new AObject304();
    A304.doSomething();
    // Will run right Up stop in that order
    
    AObject A962 = new AObject962();
    A962.doSomething();
    // Will run down left up stop in that order
    

    更多关于这种编程的信息可以在这里找到:http://en.wikipedia.org/wiki/Polymorphism_%28computer_science%29

    如果您希望能够动态更改对象的行为,可以考虑应用状态模式:http://en.wikipedia.org/wiki/State_pattern

    【讨论】:

    • 你现在如何有条件地调用一个?
    • @Ven 您在对象的实例上调用 do instance,它将执行属于该实例的代码。假设您希望这种行为是可设置的。那么你可以考虑使用状态模式:en.wikipedia.org/wiki/State_pattern.
    • 但是你如何实例化正确的类呢?您没有在这里回答主要问题。
    • 这仍然不正确,您正在执行每一个行为,而不是依赖于“i”的值。
    • i 的值在对象中表示,它不再是 var。但这取决于对象的类型。它仍然包含与 OP 的代码类似的逻辑,但没有 if/else,就像 OP 所要求的那样。 :)
    【解决方案9】:

    Wahahahahaha,你拯救了我的一天 :) 这应该有效,现在无法测试..

    public void doSomething(int i) {
    
    try {
        int x = 1/(12-i); // fails for i==12
    } catch (ArithmeticException e) {
            up();
            left();
            stop();
    }
    

    等等,尽情享受吧!

    【讨论】:

      【解决方案10】:

      在 JAVA 中可以通过使用逻辑 AND 运算符的短路来实现所需的行为,如下所示:

      public static Boolean seq12() {
          // order should be same
          up();
          left();
          stop();
          return true;
      }
      public static Boolean seq304() {
          // order should be same
          right();
          up();
          stop();
          return true;
      }
      public static Boolean seq962() {
          // order should be same
          down();
          left();
          up();
          stop();
          return true;
      }
      
      public static void doSomething(int i) {
          Boolean tmp;
          tmp = (i == 12 && seq12());
          tmp = (i == 304 && seq304());
          tmp = (i == 962 && seq962());
      }
      

      这段代码非常简单,并且依赖于逻辑与运算符仅在第一个操作数为 true 时计算第二个操作数的事实。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-22
        • 2010-10-14
        • 1970-01-01
        相关资源
        最近更新 更多