当前位置: 首页 > 知识库问答 >
问题:

将 if else 语句替换为模式

柴霖
2023-03-14

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

    public void decide(String someCondition){

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

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

           //
           someMethod("anotherParameter");

        }
        .
        .
        else{

            someMethod("elseParameter");

        }
}

因为,这看起来已经很乱了,我想如果我能在这里应用任何设计模式会更好。我研究了战略模式,但我不确定这是否会降低其他条件。有什么建议吗?

共有3个答案

越飞语
2023-03-14

Martin Fowler的一般建议是用多态替换条件。

设计模式而言,这通常是策略模式用策略替换条件逻辑。

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

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

}

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

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

}
华聪
2023-03-14

假设我们有这样的代码(与您的代码相同):

    public void decide(String someCondition) {
        if(someCondition.equals("conditionOne")) {
            someMethod("someParameter");
        }
        else if(someCondition.equals("conditionTwo")) {
            someMethod("anotherParameter");
        }
        else {
            someMethod("elseParameter");
        }
    }

假设您不想重构应用程序的其他部分,也不想更改方法签名,那么有几种可能的重构方法:

警告-您应该使用上述模式的通用版本。< br >我展示了非通用的,因为这样更容易阅读。

策略工厂方法
我们可以使用策略和工厂方法模式。我们还利用了多态性。

  private final StrategyConditionFactory strategyConditionFactory = new StrategyConditionFactory();

    public void decide(String someCondition) {
        Strategy strategy = strategyConditionFactory.getStrategy(someCondition)
                .orElseThrow(() -> new IllegalArgumentException("Wrong condition"));
        strategy.apply();
    }

最好以工厂中包含其他条件的方式设计它,并且开发人员故意调用它。在这种情况下,当条件不满足时,我们会抛出异常。或者,我们可以完全按照它所讨论的方式编写它。如果你愿意而不是 .orElseThrow(() -

的工厂方法。

    public class StrategyConditionFactory {
        private Map<String, Strategy> conditions = new HashMap<>();
    
        public StrategyConditionFactory() {
            conditions.put("conditionOne", new ConditionOneStrategy());
            conditions.put("conditionTwo", new ConditionTwoStrategy());
            //It is better to call else condition on purpose than to have it in the conditional method
            conditions.put("conditionElse", new ElseStrategy());
            //...
        }
    
        public Optional<Strategy> getStrategy(String condition) {
            return Optional.ofNullable(conditions.get(condition));
        }
    }

策略界面:

public interface Strategy {
    void apply();
}

实现:

    public class ConditionOneStrategy implements Strategy {
        @Override
        public void apply() {
            //someMethod("someParameter");
        }
    }  
    public class ConditionTwoStrategy implements Strategy {
        @Override
        public void apply() {
            //someMethod("anotherParameter")
        }
    }
    public class ElseStrategy implements Strategy {
        @Override
        public void apply() {
            //someMethod("elseParameter")
        }
    }

用法(简体):

    public void strategyFactoryApp() {
        //...
        decide("conditionOne");
        decide("conditionTwo");
        decide("conditionElse");
        //...
    }

策略工厂方法-这种特殊情况(仅参数更改)
我们可以使用这样一个事实,即在这种情况下,我们总是调用相同的方法,仅参数更改
我们使用getParameter()方法将基本策略接口更改为抽象类,并对该抽象类进行新的实现。其他代码保持不变。

public abstract class Strategy {
    public abstract String getParameter();

    public void apply() {
        someMethod(getParameter());
    }

    private void someMethod(String parameter) {
        //someAction
    }
}

实现:

public class CondtionOneStrategy extends Strategy {
    @Override
    public String getParameter() {
        return "someParameter";
    }
}
public class CondtionTwoStrategy extends Strategy {
    @Override
    public String getParameter() {
        return "anotherParameter";
    }
}
public class ElseStrategy extends Strategy {
    @Override
    public String getParameter() {
        return "elseParameter";
    }
}

enum enum有点像“工厂”< br >我们可以使用Enum来实现策略,我们可以使用Enum中的valueOf()来代替工厂方法。

    public void decide(String someCondition) {
            ConditionEnum conditionEnum = ConditionEnum.valueOf(someCondition);
            conditionEnum.apply();
        }

条件枚举:

public enum ConditionEnum {
    CONDITION_ONE {
        @Override
        public void apply() {
            //someMethod("someParameter");
        }
    },
    CONDITION_TWO {
        @Override
        public void apply() {
            //someMethod("anotherParameter");
        }
    },
    CONDITION_ELSE {
        @Override
        public void apply() {
            //someMethod("elseParameter");
        }
    };
    //...more conditions

    public abstract void apply();
}

用法(简体):

    public void enumFactoryApp() {
        //...
        decide("CONDITION_ONE");
        decide("CONDITION_TWO");
        decide("CONDITION_ELSE");
        //...
    }

请注意,当枚举类型没有具有指定名称的常量时,您将得到IllegalArgumentException

命令工厂
策略和命令之间的区别在于命令也保存状态,所以如果你有例如compute(int a,int b,String someCondition),并且你想用策略重构它,包括它的签名更改,你可以用命令将其减少为compute(int a,int b,ComputeStrategy computeStrategy),你可以把它减少到一个参数compute(ComputeCommand computeCommand)。在这种情况下,我们还利用了类似于策略模式情况的多态性。

    CommandConditionFactory commandConditionFactory = new CommandConditionFactory();

    public void decide(String someCondition) {
        Command command = commandConditionFactory.getCommand(someCondition)
                .orElseThrow(() -> new IllegalArgumentException("Wrong condition"));
        command.apply();
    }

最好以工厂中包含其他条件的方式设计它,并且开发人员故意调用它。在这种情况下,当条件不满足时,我们会抛出异常。或者,我们可以完全按照它所讨论的方式编写它。如果你愿意而不是 .orElseThrow(() -

CommandConditionFactory(工厂方法):

public class CommandConditionFactory {
    private Map<String, Command> conditions = new HashMap<>();

    public CommandConditionFactory() {
        conditions.put("conditionOne", new ConditionOneCommand("someParameter"));
        conditions.put("conditionTwo", new ConditionTwoCommand("anotherParameter"));
        //It is better to call else condition on purpose than to have it in the conditional method
        conditions.put("conditionElse", new ElseCommand("elseParameter"));
        //...
    }

    public Optional<Command> getCommand(String condition) {
        return Optional.ofNullable(conditions.get(condition));
    }
}

命令界面:

public interface Command {
    void apply();
}

实现(有一些冗余,但它是为了展示命令在更一般的情况下应该是如何看的,其中我们有三个不同的方法而不是某些方法()):

public class ConditionOneCommand implements Command {
    private final String parameter;

    public ConditionOneCommand(String parameter) {
        this.parameter = parameter;
    }

    @Override
    public void apply() {
        //someMethod(parameter);
    }
}
public class ConditionTwoCommand implements Command {
    private final String parameter;

    public ConditionTwoCommand(String parameter) {
        this.parameter = parameter;
    }

    @Override
    public void apply() {
        //someMethod(parameter);
    }
}
public class ElseCommand implements Command {
    private final String parameter;

    public ElseCommand(String parameter) {
        this.parameter = parameter;
    }

    @Override
    public void apply() {
        //someMethod(parameter);
    }
}

用法(简体):

    public void commandFactoryApp() {
        //...
        decide("conditionOne");
        decide("conditionTwo");
        decide("conditionElse");
        //...
    }

命令工厂-这种特殊情况
这实际上不是一个真正的命令模式,只是一个派生模式。它利用了这样一个事实:在这种情况下,我们总是调用相同的方法someMethod(参数),而只有参数发生了变化
抽象类:

public abstract class Command {
    abstract void apply();

    protected void someMethod(String parameter) {
        //someAction
    }
}

实施(所有3个有条件的情况相同):

public class CommandImpl extends Command {
    private final String parameter;

    public CommandImpl (String parameter) {
        this.parameter = parameter;
    }

    @Override
    public void apply(){
        someMethod(parameter);
    }
}

工厂,请注意,只有一个命令实现,只有参数更改:

public class CommandConditionFactory {
    Map<String, Command> conditions = new HashMap<>();

    public CommandConditionFactory() {
        conditions.put("conditionOne", new CommandImpl("someParameter"));
        conditions.put("conditionTwo", new CommandImpl("anotherParameter"));
        //It is better to call else condition on purpose than to have it in the conditional method
        conditions.put("conditionElse", new CommandImpl("elseParameter"));
        //...
    }

    public Optional<Command> getCommand(String condition) {
        return Optional.ofNullable(conditions.get(condition));
    }
}

嵌套的if < br >注意,即使你有嵌套的if,有时也可以重构它们并使用上面提到的技术之一。假设我们有以下代码:

    public void decide2(String someCondition, String nestedCondition) {
        if(someCondition.equals("conditionOne")) {
            if(nestedCondition.equals("nestedConditionOne")){
                someLogic1();
            }
            else if(nestedCondition.equals("nestedConditionTwo")){
                someLogic2();
            }
        }
        else if(someCondition.equals("conditionTwo")) {
            if(nestedCondition.equals("nestedConditionThree")){
                someLogic3();
            }
            else if(nestedCondition.equals("nestedConditionFour")){
                someLogic4();
            }
        }
    }

您可以使用数学逻辑规则重构它:

    public void decide2(String someCondition, String nestedCondition) {
        if(someCondition.equals("conditionOne")
                && nestedCondition.equals("nestedConditionOne")) {
            someLogic1();
        }
        else if(someCondition.equals("conditionOne")
                && nestedCondition.equals("nestedConditionTwo")) {
            someLogic2();
        }
        else if(someCondition.equals("conditionTwo")
                && nestedCondition.equals("nestedConditionThree")) {
            someLogic3();
        }
        else if(someCondition.equals("conditionTwo")
                && nestedCondition.equals("nestedConditionFour")) {
            someLogic4();
        }
    }

然后你可以使用策略、枚举或命令。你只有一对字符串

决策表
当您有无法重构的嵌套ifs时,您可以实现自己的决策表或使用一些现成的决策表解决方案。我不会在那里给出实现。

规则引擎
当您有嵌套的ifs无法如前所述重构时,您也可以实现自己的简单规则引擎。只有当您有许多嵌套的ifs时才应该使用它,否则它是形式对内容的胜利。
对于非常复杂的业务逻辑,有专业的规则引擎,如Drools。
我不会在那里给出实现。

还有一件事
在您给出的示例中,很有可能有人引入了这些 ifs,但它们完全是多余的。我们可以通过尝试重构决定方法签名来检查它,使其采用其他参数并重构调用我们方法的周围代码。通过这样做,我们摆脱了我们的工厂方法。有一些示例展示了当这些 if 是冗余时代码的外观。

战略< br >决策方法:

    public void decide(Strategy strategy) {
        strategy.apply();
    }

用法(简体):

    public void strategyApp() {
        //...
        decide(new ConditionOneStrategy());
        decide(new ConditionTwoStrategy());
        decide(new ElseStrategy());
        //...
    }

枚举
决定方法:

    public void decide(ConditionEnum conditionEnum) {
        conditionEnum.apply();
    }

用法(简体):

    public void enumApp() {
        //...
        decide(ConditionEnum.CONDITION_ONE);
        decide(ConditionEnum.CONDITION_TWO);
        decide(ConditionEnum.CONDITION_ELSE);
        //...
    }

命令
决定方法:

    public void decide(Command command) {
        command.apply();
    }

用法(简体):

    public void commandApp() {
        //...
        decide(new ConditionOneCommand("someParameter"));
        decide(new ConditionTwoCommand("anotherParameter"));
        decide(new ElseCommand("elseParameter"));
        //...
    }

实际上这是非常特殊的情况,在某些情况下,例如我们必须使用像String这样的简单类型,因为它来自外部系统或条件基于输入中的整数,因此我们无法轻松重构代码。

单修德
2023-03-14

这是Refactoring to Patterns书中使用命令替换条件调度程序的经典版本。

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

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

然后不是你的if/否则代码,而是:

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

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

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

 Handler defaultHandler = ...

if(commandMap.containsKey(someCondition)){
    commandMap.get(someCondition).handle(this);
}else{
    defaultHandler.handle(this);
}
 类似资料:
  • 基于SO上的各种线程(例如。用设计模式替换多个If\Else或用模式替换if else语句)我知道我可以用< code >命令模式替换多个< code>if\else语句。 但对于我这个级别的人来说,答案远不是简单或详细的。我会有60个会阻塞。我做了一些研究,发现命令模式是最好的。搜索关于如何一步一步的教程似乎很难,因为我发现的都是复杂的事情。相信我,如果我没有在网上做大量的重新搜索和放弃,我不会

  • 问题内容: 我需要使用REPLACE编写一条sql更新语句。字符串看起来像’SE * 88 * 000000001’。我需要替换两个星号“ *”之间的数字。除了要替换的数字始终在两个星号之间之外,这里没有其他模式。在这种情况下可以使用通配符吗? 感谢你的帮助。 谢谢! 问题答案: 或者,如果要替换的是一个特定的数字,那么它将更加简单:

  • 我用R编写了以下代码,效果很好。但是,假设我必须对具有多个级别的因子变量应用类似的代码(

  • 问题内容: 我想用Python编写一个函数,该函数根据输入索引的值返回不同的固定值。 在其他语言中,我将使用语句,但是Python似乎没有语句。在这种情况下,推荐的Python解决方案是什么? 问题答案: 你可以使用字典:

  • 我们的老师让我们创建一个关于给定情况的java程序,即使用if/else的每小时工资率,这就是我得出的结果,我对此感到高兴(我只是一个初学者)。接下来的指令是用switch语句替换if/else。他还没有讨论switch语句。我试图搜索它们,但我无法理解。请帮忙。非常感谢。 这就是确切的指示:1。使用if/else构造编写一个程序,该程序将根据工作小时数计算人员工资。注意ff:工资率为每小时35菲

  • 我想用Python编写一个函数,根据输入索引的值返回不同的固定值。 在其他语言中,我会使用或语句,但Python似乎没有语句。在这个场景中,推荐的Python解决方案是什么?