Устранение суждения if-else об элегантном коде

спецификация кода

Раздутый пример

if-else

public int calculate(int a, int b, String operator) {
 int result = Integer.MIN_VALUE;
 if ("add".equals(operator)) {
 result = a + b;
 } else if ("multiply".equals(operator)) {
 result = a * b;
 } else if ("divide".equals(operator)) {
 result = a / b;
 } else if ("subtract".equals(operator)) {
 result = a - b;
 } else if ("modulo".equals(operator)) {
 result = a % b;
 }
 return result;
 }

case-switch

 public int calculateUsingSwitch(int a, int b, String operator) {
 int result = 0;
 switch (operator) {
 case "add":
 result = a + b;
 break;
 case "multiply":
 result = a * b;
 break;
 case "divide":
 result = a / b;
 break;
 case "subtract":
 result = a - b;
 break;
 case "modulo":
 result = a % b;
 break;
 default:
 result = Integer.MIN_VALUE;
 }
 return result;
 }

рефакторинг

заводской рефакторинг

  1. абстрактный интерфейс Operation.java
public interface Operation {
 int apply(int a, int b);
}
  1. Дополнение реализует Addition.java:
public class Addition implements Operation {
 @Override
 public int apply(int a, int b) {
 return a + b;
 }
}
  1. Реализация вычитания Subtraction.java
public class Subtraction implements Operation {
 @Override public int apply(int a, int b) {
 return a - b;
 }
}
  1. Реализация умножения Multiplication.java
public class Multiplication implements Operation {
 @Override public int apply(int a, int b) {
 return a*b;
 }
}
  1. Дивизион достиг Division.java
public class Division implements Operation {
 @Override public int apply(int a, int b) {
 return a / b;
 }
}
  1. Остаток достижения Modulo.java
public class Modulo implements Operation {
 @Override public int apply(int a, int b) {
 return a % b;
 }
}
  1. Фабричный класс OperatorFactory.java
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class OperatorFactory {
 static Map<String, Operation> operationMap = new HashMap<>();
 static {
 operationMap.put("add", new Addition());
 operationMap.put("divide", new Division());
 operationMap.put("multiply", new Multiplication());
 operationMap.put("subtract", new Subtraction());
 operationMap.put("modulo", new Modulo());
 }
 public static Optional<Operation> getOperation(String operation) {
 return Optional.ofNullable(operationMap.get(operation));
 }
}
  1. Пример использования
public int calculateUsingFactory(int a, int b, String operator) {
 Operation targetOperation = OperatorFactory
 .getOperation(operator)
 .orElseThrow(() -> new IllegalArgumentException("Invalid Operator"));
 return targetOperation.apply(a, b);
} 

Рефакторинг метода перечисления

  1. Перечисление реализует Operator.java
public enum Operator {
 ADD {
 @Override
 public int apply(int a, int b) {
 return a + b;
 }
 },
 MULTIPLY {
 @Override
 public int apply(int a, int b) {
 return a * b;
 }
 },
 SUBTRACT {
 @Override
 public int apply(int a, int b) {
 return a - b;
 }
 },
 DIVIDE {
 @Override
 public int apply(int a, int b) {
 return a / b;
 }
 },
 MODULO {
 @Override
 public int apply(int a, int b) {
 return a % b;
 }
 };
 public abstract int apply(int a, int b);
}
  1. Оператор инкапсуляции к Calculator.java
 public int calculate(int a, int b, Operator operator) {
 return operator.apply(a, b);
 }
  1. Пример использования
@Test
public void whenCalculateUsingEnumOperator_thenReturnCorrectResult() {
 Calculator calculator = new Calculator();
 int result = calculator.calculate(3, 4, Operator.valueOf("ADD"));
 assertEquals(7, result);
}

Командной режим

  1. Абстрактные интерфейсы
public interface Command {
 Integer execute();
}
  1. Класс реализации
package com.baeldung.reducingIfElse;
public class AddCommand implements Command {
 private int a;
 private int b;
 public AddCommand(int a, int b) {
 this.a = a;
 this.b = b;
 }
 @Override
 public Integer execute() {
 return a + b;
 }
}
  1. Упаковка
 public int calculate(Command command) {
 return command.execute();
 }
  1. тестовая демонстрация
@Test
public void whenCalculateUsingCommand_thenReturnCorrectResult() {
 Calculator calculator = new Calculator();
 int result = calculator.calculate(new AddCommand(3, 7));
 assertEquals(10, result);
}

Рефакторинг движка правил

  1. абстрактные правила
public interface Rule {
 boolean evaluate(Expression expression);
 Result getResult();
}
  1. Реализовать правило AddRule.java
public class AddRule implements Rule {
 private int result;
 @Override
 public boolean evaluate(Expression expression) {
 boolean evalResult = false;
 if (expression.getOperator() == Operator.ADD) {
 this.result = expression.getX() + expression.getY();
 evalResult = true;
 }
 return evalResult;
 }
 @Override
 public Result getResult() {
 return new Result(result);
 }
}

Где: вернуть результат

public class Result {
 int value;
 public Result(int value) {
 this.value = value;
 }
 public int getValue() {
 return value;
 }
}

выражение

public class Expression {
 private Integer x;
 private Integer y;
 private Operator operator;
 public Expression(Integer x, Integer y, Operator operator) {
 this.x = x;
 this.y = y;
 this.operator = operator;
 }
 public Integer getX() {
 return x;
 }
 public Integer getY() {
 return y;
 }
 public Operator getOperator() {
 return operator;
 }
}

Механизм правил RuleEngine.java

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class RuleEngine {
 private static List<Rule> rules = new ArrayList<>();
 static {
 rules.add(new AddRule());
 }
 public Result process(Expression expression) {
 Rule rule = rules.stream()
 .filter(r -> r.evaluate(expression))
 .findFirst()
 .orElseThrow(() -> new IllegalArgumentException("Expression does not matches any Rule"));
 return rule.getResult();
 }
}
  1. тестовая демонстрация
@Test
public void whenNumbersGivenToRuleEngine_thenReturnCorrectResult() {
 Expression expression = new Expression(5, 5, Operator.ADD);
 RuleEngine engine = new RuleEngine();
 Result result = engine.process(expression);
 
 assertNotNull(result);
 assertEquals(10, result.getValue());
}

резюме

Для лучшего повторного использования кода, удобочитаемости, надежности и удобства обслуживания мы попытаемся преобразовать IF/ELSE или переключатель регистра, используя фабричные методы, методы перечисления, шаблоны команд и методы механизма правил.Попробуйте и, наконец, оцените свой код, используя шесть принципы шаблонов проектирования.