Альтернатива операторов 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, хотя с объектами вместо Map
s, функции (вероятно, анонимный) вместо Runnable
s, 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());
}
этот код является довольно прямо вперед и опирается на тот факт, что логический оператор оценивает только второй операнд, если первый правда.