Альтернатива операторов if-else и switch

У меня есть следующий код на 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.

10 ответов


если вы можете использовать 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) {}
}

если только if и switch операторы не допускаются, замените все 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()
  );
}

вот простой способ сделать это в 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);

функции могут быть добавлены / упорядочены просто путем редактирования переменной карты.


вы можете сделать словарь ввода в действие. В 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
}

если-иначе нет строгой необходимости, но без него вы получите NullPointerException если i не является ожидаемым значением-то есть одним из значений, которые вы помещаете в карту.

идея аналогична в JavaScript, хотя с объектами вместо Maps, функции (вероятно, анонимный) вместо Runnables, etc.


этот код на Java 8. В Java 7 и ниже вы бы сделали:

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


Wahahahahahaha, вы спасли мой день :) это должно работать, нет способа проверить прямо сейчас..

public void doSomething(int i) {

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

и так далее, наслаждайтесь!


затем сделайте это с помощью 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;
    }
}

Послушай, естественно вы должны проверить условный оператор с условным выражением! Теперь, если вы не хотите этого делать, вы можете сделать это неестественно так:

сначала сделайте это для всех методов (вверх,вниз,...)

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 не имеет делегатов!


для js u может попробовать следующее:

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

эта проблема может быть решена с использованием методов ООП.

в 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 на экземпляре конкретного класса вызовет соответствующее поведение. Так что нет больше, если / 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


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

желаемое поведение может быть достигнуто в 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());
}

этот код является довольно прямо вперед и опирается на тот факт, что логический оператор оценивает только второй операнд, если первый правда.