【问题标题】:Cleaning up java code, multiple if statements清理java代码,多个if语句
【发布时间】:2016-10-15 20:52:54
【问题描述】:

我应该清理一个 java 代码,去掉很多东西,但是应该还有什么要清理的,也许以某种方式去掉多个 if 语句,而不完全重写这段代码?似乎无法弄清楚,因为它们是如此不同,以至于将它们堆叠在一个“如果”中。有什么想法吗?

 public class Calc {
           // employee types
           public static final int SELLER;
           public static final int COOK;
           public static final int CHIEF;



       public static void main(final String[] args) {
              Calc c = new Calc();
              System.err.println(c.pay(CHIEF) + " should be 66");
       }

       private int pay(final int type, final int h) {
              int Sum = 0;
              if (type == SELLER) {
                     if (h > 8) { 
                           Sum = 20 * (h - 8);  
                           Sum += 80;
                     } else {
                           Sum += 10 * h;
                     }
              }
              if (type == COOK) {
                     if (h > 8) { 
                           Sum = 30 * (h - 8); 
                           Sum += 15 * 8;
                     } else {
                           Sum += 15 * h;
                     }
              }
              if (type == CHIEF) {
                     if (h > 8) { 
                           Sum = 66 * (h - 8); 
                           Sum += 22 * 8;
                     } else {
                           Sum += 22 * h;
                     }
              }
              if (h > 20) {
                     if (type == SELLER) {
                           Sum += 10;
                     }
                     if (type == COOK) {
                           Sum += 20;
                     }
                     if (type == CHIEF) {
                           Sum += 30;
                     }
              }
              return Sum;
       }
}

【问题讨论】:

    标签: java code-cleanup


    【解决方案1】:

    您编写的代码纯粹是程序性的,在大多数情况下,在使用 Java 等面向对象的语言编写时被认为是一种不好的做法。您应该了解多态的强大功能,并且不应该手动执行类型检查:

    if (type == COOK) { //Avoid doing this in OO languages!
    

    您应该将您的域实体(员工)视为对象,并且每种特定类型的员工都可以定义自己的工资计算规则。

    让我们用单个抽象方法int calculatePay(int h)创建一个抽象类Employee:

    public abstract class Employee {
        abstract int calculatePay(int h);
    }
    

    abstract表示这个方法没有实际实现,但是所有计算工资的逻辑都会放在子类Seller、Cook和Chief中:

    public class Cook extends Employee {
    
        public Cook() {}
    
        int calculatePay(int h) {
            int sum = (h > 20) ? 20 : 0;
            if (h > 8) {
                sum = 30 * (h - 8);
                sum += 15 * 8;
            } else {
                sum += 15 * h;
            }
            return sum;
        }
    }
    

    注意这一行:

        int sum = (h > 20) ? 20 : 0;
    

    这是三元运算符。有时它适用于表达式中的条件赋值。因此,当h 大于 20 时,我们将 sum 变量初始化为 20,否则初始化为 0。现在我们不再在方法末尾使用额外的if 语句。

    现在每个员工都负责计算自己的工资,无需在 PayCalculator 类中执行类型检查 - 在运行时动态解析根据参数类型执行哪些代码:

    public class PayCalculator {
    
        int pay(Employee e, int hours) {
            return e.calculatePay(hours);
        }
    
        public static void main(String[] args) {
            Seller seller = new Seller();
            Cook cook = new Cook();
            Chief chief = new Chief();
    
            PayCalculator calc = new PayCalculator();
    
            System.out.println("Seller is payed " + calc.pay(seller, 15));
            System.out.println("Cook is payed " + calc.pay(cook, 10));
            System.out.println("Chief is payed " + calc.pay(chief, 22));
        }
    }
    

    这称为多态。如果您对这个术语不熟悉,您可以阅读 OOP 基础中的 Oracle 教程:https://docs.oracle.com/javase/tutorial/java/concepts/index.html

    Thinking in Java Bruce Eckel 的书也很好地解释了基本的 OOP 概念。

    【讨论】:

    • 这是一个很好的解释,当然!这实际上是我的老师写的,可能是为了丑陋。我有一种感觉,你的方法可以以某种方式实现,但我无法做到这一点。感谢您让我的学习曲线更轻松!
    【解决方案2】:

    java.util.Map 节省大量 if/else,并使用Enum 作为用户的选择

    public class X {
    
        public enum Type {
            SELLER, COOK, CHIEF
        }
    
        private Map<Type, Integer> constantValue1;
        private Map<Type, Integer> constantValue2;
        private Map<Type, Integer> additionalValue;
    
        public X() {
            initialConstantValue1();
            initialConstantValue2();
            initialAdditionalValue();
        }
    
        private void initialConstantValue1() {
            constantValue1 = new HashMap<>();
            constantValue1.put(Type.SELLER, 20);
            constantValue1.put(Type.COOK, 30);
            constantValue1.put(Type.CHIEF, 66);
        }
    
        private void initialConstantValue2() {
            constantValue2 = new HashMap<>();
            constantValue2.put(Type.SELLER, 10);
            constantValue2.put(Type.COOK, 15);
            constantValue2.put(Type.CHIEF, 22);
        }
    
        private void initialAdditionalValue() {
            additionalValue = new HashMap<>();
            additionalValue.put(Type.SELLER, 10);
            additionalValue.put(Type.COOK, 20);
            additionalValue.put(Type.CHIEF, 30);
        }
    
        int pay(final Type type, final int h) {
            int sum = 0;
            if (h > 8) {
                sum = constantValue1.get(type) * (h - 8);
                sum += constantValue2.get(type) * 8;
            }
            else {
                sum += constantValue2.get(type) * h;
            }
            if (h > 20) {
                sum += additionalValue.get(type);
            }
            return sum;
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      这是在pay 方法中使用最少的if 语句清理或实现它的另一种方法。将员工类型移动到enum,然后每个enum 类型都有自己的薪酬计算。像这样:

      package sandbox;
      
      public enum Employee {
          SELLER() {
              @Override 
              int pay(int h) {
                  int sum = (h > 20) ? 10 : 0;
                  if (h > 8) { 
                      sum = 20 * (h - 8);  
                      sum += 80;
                  } else {
                      sum += 10 * h;
                  }
                  
                  return sum;
              }
          },
          COOK() {
              @Override 
              int pay(int h) {
                  int sum = (h > 20) ? 20 : 0;
                  if (h > 8) { 
                      sum = 30 * (h - 8);  
                      sum += 15 * 8;
                  } else {
                      sum += 15 * h;
                  }
                  
                  return sum;
              }
          },
          CHIEF() {
              @Override 
              int pay(int h) {
                  int sum = (h > 20) ? 30 : 0;
                  if (h > 8) { 
                      sum = 66 * (h - 8);  
                      sum += 22 * 8;
                  } else {
                      sum += 22 * h;
                  }
                  
                  return sum;
              }       
          };
          
          abstract int pay(int h);
      }
      

      还有跑步者……

      package sandbox;
      
      public class Main {
      
          public static void main(String[] args) {
              System.out.println(Employee.SELLER.pay(5));
              System.out.println(Employee.COOK.pay(5));
              System.out.println(Employee.CHIEF.pay(5));
          }
      }
      

      【讨论】:

        【解决方案4】:

        在 Java 8 中,该语言获得了各种可用于功能类型清理的功能位。

            import java.util.EnumMap;
            import java.util.function.IntFunction;
        
            public class Calc8 {
        
                public enum Employee {
                    SELLER, COOK, CHIEF;
                }
        
                private final EnumMap<Employee, IntFunction<Integer>> map = new EnumMap<>(Employee.class);
        
                public Calc8() {
                    map.put(Employee.SELLER, h -> {
                        int sum = h > 8 ? 20 * (h - 8) + 80 : 10 * h;
                        return h > 20 ? sum + 10 : sum;
                    });
                    map.put(Employee.COOK, h -> {
                        int sum = h > 8 ? 30 * (h - 8) + (15 * 8) : 15 * h;
                        return h > 20 ? sum + 20 : sum;
        
                    });
                    map.put(Employee.CHIEF, h -> {
                        int sum = h > 8 ? 66 * (h - 8) + (22 * 8) : 22 * h;
                        return h > 20 ? sum + 30 : sum;
                    });
                }
        
                public int evaluate(Employee e, int value) {
                    return map.get(e).apply(3);
                }
        
                public static void main(final String[] args) {
                    Calc8 c = new Calc8();
                    System.err.println(c.evaluate(Employee.CHIEF, 3) + " should be 66");
                }
            }
        

        【讨论】:

        • 您可能不应该为每个Calc8 实例构建地图。此外,它甚至不应该是一个类。
        • 也许,取决于用例。方法Calc8.evaluate() 可以证明类的存在,因为它抽象了实现。
        • 这实际上是我的第一个想法,为什么不为每个 Calc8 实例构建一个 Map?
        • 因为map的值没有状态,一个实例就够了。这可以通过将其设为静态或将 Calc8 设为单例来实现。
        【解决方案5】:

        为 pay 函数中的类型编写一个 switch 块,而不是使用多个 if else 语句。 不要给出 type == SELLER ,而是创建一个正确的名称并进行比较。

        还有一个接口对Employees来说很好,用工厂模式来获取对象。

        对于代码清理,您还可以添加插件,例如: https://www.sonarlint.org/

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-06-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-02-11
          • 1970-01-01
          • 2020-02-16
          相关资源
          最近更新 更多