Java 用模式替换 if else 语句

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28049094/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 05:31:38  来源:igfitidea点击:

Replacing if else statement with pattern

javaoopdesign-patterns

提问by cosmos

I have a if else statement which might grow in the near future.

我有一个 if else 语句,它可能会在不久的将来增长。

    public void decide(String someCondition){

        if(someCondition.equals("conditionOne")){
            //
            someMethod("someParameter");

        }else if(someCondition.equals("conditionTwo")){

           //
           someMethod("anotherParameter");

        }
        .
        .
        else{

            someMethod("elseParameter");

        }
}

Since, this is already looking messy, I think it would be better if I can apply any design patterns here. I looked into Strategy pattern but I am not sure if that will reduce if else condition here. Any suggestions?

因为,这看起来已经很乱了,我认为如果我可以在这里应用任何设计模式会更好。我研究了策略模式,但我不确定这是否会减少这里的其他条件。有什么建议?

采纳答案by dkatzel

This is a classic Replace Condition dispatcher with Commandin the Refactoring to Patterns book.

这是Refactoring to Patterns 书中的经典Replace Condition dispatcher with Command

enter image description here

在此处输入图片说明

Basically you make a Commandobject for each of the blocks of code in your old if/else group and then make a Map of those commands where the keys are your condition Strings

基本上,您Command为旧的 if/else 组中的每个代码块创建一个对象,然后为这些命令创建一个 Map,其中键是您的条件字符串

interface Handler{
    void handle( myObject o);
}


 Map<String, Handler> commandMap = new HashMap<>();
 //feel free to factor these out to their own class or
 //if using Java 8 use the new Lambda syntax
 commandMap.put("conditionOne", new Handler(){
         void handle(MyObject o){
                //get desired parameters from MyObject and do stuff
          }
 });
 ...

Then instead of your if/else code it is instead:

然后代替您的 if/else 代码:

 commandMap.get(someCondition).handle(this);

Now if you need to later add new commands, you just add to the hash.

现在,如果您以后需要添加新命令,只需添加到哈希中即可。

If you want to handle a default case, you can use the Null Objectpattern to handle the case where a condition isn't in the Map.

如果要处理默认情况,可以使用Null Object模式来处理条件不在 Map 中的情况。

 Handler defaultHandler = ...

if(commandMap.containsKey(someCondition)){
    commandMap.get(someCondition).handle(this);
}else{
    defaultHandler.handle(this);
}

回答by mehmetakcay

I guess you must have already considered it, but if you are using JDK 7 or above, you can switch on strings. That way your code can look cleaner than a bunch of if-else statements.

我想你一定已经考虑过了,但是如果你使用的是 JDK 7 或更高版本,你可以打开字符串。这样你的代码看起来比一堆 if-else 语句更简洁。

回答by Puce

The general recommendation by Martin Fowler is to Replace Conditional with Polymorphism.

Martin Fowler 的一般建议是 将 Conditional 替换为 Polymorphism

In terms of design patterns this would often be the Strategy Pattern Replace Conditional Logic with Strategy.

在设计模式方面,这通常是 Strategy Pattern Replace Conditional Logic with Strategy

If you have a small, finite setof conditions, I recommend to use an enumto implement the Strategy Pattern (provide an abstract method in the enum and override it for each constant).

如果你有一个小的、有限的条件,我建议使用枚举来实现策略模式(在枚举中提供一个抽象方法并为每个常量覆盖它)。

public enum SomeCondition{
   CONDITION_ONE{

       public void someMethod(MyClass myClass){
              //...
       }
   },

   CONDITION_TWO{

       public void someMethod(MyClass myClass){
       }

   }

   public abstract void someMethod(MyClass myClass);

}

public class MyClass{
//...
    public void decide(SomeCondition someCondition){
        someCondition.someMethod(this);
    }

}

If it's really just a parameter you want to pick, then you could define the enum like this instead:

如果它真的只是你想选择的一个参数,那么你可以像这样定义枚举:

public enum SomeCondition{
   CONDITION_ONE("parameterOne"),

   CONDITION_TWO("parameterTwo");

   private final String parameter;

   private SomeCondition(String parameter){
       this.parameter = parameter;
   }

   public String getParameter(){
       return parameter;
   }

}


public class MyClass{
//...
    public void decide(SomeCondition someCondition){
        someMethod(someCondition.getParameter());
    }

}

回答by Andrey Chertok

Another way to solve the current problem is to use Factory Pattern. This provides functionality to extract a factory method that returns an object of a given type and performs the operation based on the concrete object behavior.

解决当前问题的另一种方法是使用工厂模式。这提供了提取工厂方法的功能,该方法返回给定类型的对象并根据具体的对象行为执行操作。

public interface Operation {

String process(String a, String b);
}

The method takes two string as input and returns the result.

该方法将两个字符串作为输入并返回结果。

public class Concatenation implements Operation {

  @Override
  public String process(String a, String b) {
    return a.concat(b);
  }
}

public class Join implements Operation {

  @Override
  public String process(String a, String b) {
    return String.join(", ", a, b);
  }
}

And then we should define a factory class which returns instances of Operation based on the given operator:

然后我们应该定义一个工厂类,它根据给定的运算符返回 Operation 的实例:

public class OperatorFactory {

  static Map<String, Operation> operationMap = new HashMap<>();

  static {
    operationMap.put("concatenation", new Concatenation());
    operationMap.put("join", new Join());
    // more operators
  }

  public static Optional<Operation> getOperation(String operator) {
    return Optional.ofNullable(operationMap.get(operator));
  }
}

And now we can use it:

现在我们可以使用它:

public class SomeServiceClass {

      public String processUsingFactory(String a, String b, String operationName) {
        Operation operation = OperatorFactory
            .getOperation(operationName)
            .orElseThrow(() -> new IllegalArgumentException("Invalid Operation"));

        return operation.process(a, b);
      }
    }