Перевод | Как заменить сложные операторы if в Java

Шаблоны проектирования
Перевод | Как заменить сложные операторы if в Java

Оригинальный текст взят из блога инженера baeldung,портал

Подписывайтесь на насИзбранное, все последние переведенные статьи здесь.

1 Обзор

Структура принятия решения занимает важный этап в большинстве языков программирования. Но мы часто перегружены тоннами встроенных операторов if, которые делают код нечитаемым и непригодным для сопровождения.

В этом уроке мы рассмотрим различные альтернативы встроенным операторам if. Давайте рассмотрим способы упростить наш код.

2. Тематическое исследование

Часто мы сталкиваемся с некоторой бизнес-логикой, которая должна выполнять ряд условных операций, и каждую из них нужно обрабатывать по-разному.

Чтобы продемонстрировать, давайте рассмотрим пример класса Calculator. Выше приведен метод, который принимает два параметра числового типа, параметр оператора и числовое возвращаемое значение на основе операции:

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;
    }
    return result;
}

Обычно мы также можем использовать оператор switch для работы:

public int calculateUsingSwitch(int a, int b, String operator) {
    switch (operator) {
    case "add":
        result = a + b;
        break;
    // other cases    
    }
    return result;
}

В типичном процессе разработки операторы if делают программу раздутой и сложной. Более того, оператор switch подходит не для всех сценариев, когда условия сложные, оператор switch бесполезен.

Другой эффект программирования с вложенными условными объявлениями заключается в том, что это делает программы неуправляемыми. Например, если нам нужно добавить новое действие, нам нужно добавить новое условие if и реализацию условия.

3. Рефакторинг

Давайте попробуем заменить этот сложный оператор if чем-то более кратким и управляемым.

3.1 Заводской класс

Много раз мы часто сталкиваемся со многими условными операторами, которые используются для обработки аналогичных операций в каждой ветви. Это дает нам представление,Извлеките фабричный класс, который возвращает объект конкретного типа и выполняет действия на основе поведения конкретного объекта..

Например, ниже давайте определимapplyметоддействоватьинтерфейс

public interface Operation {
    int apply(int a, int b);
}

Этот метод принимает два числовых параметра и числовой возврат. Давайте определим класс, реализующий сложение:

public class Addition implements Operation {
    @Override
    public int apply(int a, int b) {
        return a + b;
    }
}

Теперь мы реализуем класс проекта, который возвращает экземпляр операции на основе заданного оператора:

public class OperatorFactory {
    static Map<String, Operation> operationMap = new HashMap<>();
    static {
        operationMap.put("add", new Addition());
        operationMap.put("divide", new Division());
        // more operators
    }
 
    public static Optional<Operation> getOperation(String operator) {
        return Optional.ofNullable(operationMap.get(operator));
    }
}

сейчас наCalculatorclass, мы можем запросить фабрику, чтобы получить связанные операции и применить их к ним:

public int calculateUsingFactory(int a, int b, String operator) {
    Operation targetOperation = OperatorFactory
      .getOperation(operator)
      .orElseThrow(() -> new IllegalArgumentException("Invalid Operator"));
    return targetOperation.apply(a, b);
}

В этом примере мы можем увидеть, как делегировать логические бизнес-обязанности ряду слабо связанных объектов через фабричный класс. Но просто перенос вложенного оператора if в фабричный класс явно не соответствует нашей цели.

Как альтернатива,Мы можем сделать это, поддерживая репозиторий объектов, которые можно быстро запрашивать.map(карта), в видеOperatorFactory#operationMap, для достижения нашей цели. Мы также можем определить объекты карты во время выполнения и настроить их для поиска.

3.2 Использование перечислений

В дополнение к использованию объектов карты (карты) мы также можем использовать перечисления для обозначения конкретных логических операций. После этого мы можем использовать его для замены вложенных операторов if или операторов swtich. Для другой обработки мы также можем использовать их как фабрики объектов и организовывать операции, связанные с бизнес-логикой.

Это уменьшает количество вложенных операторов if и делегирует бизнес-ответственность независимым операторам.перечислитьв переменной.

Давайте посмотрим, как это реализовать. Во-первых, нам нужно определить класс перечисления:

public enum Operator {
    ADD, MULTIPLY, SUBTRACT, DIVIDE
}

Как мы видим, эти значения являются метками для разных операторов и используются в последующих вычислениях. Подобно вложенным операторам if и switch, мы можем использовать эти значения в качестве опций. Но в отличие от них, давайте разработаем альтернативу, делегирующую логику самому перечислению.

Мы определяем методы для каждого перечисления и выполняем вычисления, например:

ADD {
    @Override
    public int apply(int a, int b) {
        return a + b;
    }
},
// other operators
 
public abstract int apply(int a, int b);

Затем в классе Calculator мы также определяем метод для выполнения действия:

public int calculate(int a, int b, Operator operator) {
    return operator.apply(a, b);
}

Теперь мы можем пройтииспользоватьOperator#valueOf()метод преобразования строки в оператордля вызова метода:

@Test
public void whenCalculateUsingEnumOperator_thenReturnCorrectResult() {
    Calculator calculator = new Calculator();
    int result = calculator.calculate(3, 4, Operator.valueOf("ADD"));
    assertEquals(7, result);
}

3.3 Шаблон команды

В предыдущем обсуждении мы видели использование фабричного класса для возврата соответствующего экземпляра бизнес-объекта для указанного оператора.Позже экземпляр бизнес-объекта будет использоваться в последующем Клакуляторе для выполнения вычислительных операций.

Мы также можем спроектироватьCalculator#calculateметод для получения команды, которая может выполнить ввод. Это еще один способ заменить вложенные операторы if.

Сначала мы определяемCommandинтерфейс:

public interface Command {
    Integer execute();
}

Затем реализуем один изAddCommand:

public class AddCommand implements Command {
    // Instance variables
 
    public AddCommand(int a, int b) {
        this.a = a;
        this.b = b;
    }
 
    @Override
    public Integer execute() {
        return a + b;
    }
}

Наконец, давайте определим новый метод в классе Calculator для получения и выполнения действий:

public int calculate(Command command) {
    return command.execute();
}

Создав экземпляр объекта AddCommand и передав его в качестве параметраCalculator#calculateМетод, используемый для вызова метода расчета:

@Test
public void whenCalculateUsingCommand_thenReturnCorrectResult() {
    Calculator calculator = new Calculator();
    int result = calculator.calculate(new AddCommand(3, 7));
    assertEquals(10, result);
}

3.4 механизм правил

Когда мы заканчиваем тем, что пишем много вложенных операторов if, каждое условие описывает конкретное бизнес-правило, которое оценивает выполнение правильной логической операции. Механизм правил убирает эту сложную траву из основного кода.Механизм правил используется для оценки правил и возврата результатов на основе входных данных..

Давайте поэкспериментируем, разработав простой механизм правил. Этот двигатель достигается за счет набораправилоиметь дело свыражение, а из выбранныхправилоВернуть результат. Во-первых, мы определяемправилоинтерфейс:

public interface Rule {
    boolean evaluate(Expression expression);
    Result getResult();
}

Далее давайте реализуем механизм правил:

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

этодвигатель правилполучитьвыражениеи вернутьсяResult. Теперь мы проектируемOperatorобъектвыражение(Выражение) класс:

public class Expression {
    private Integer x;
    private Integer y;
    private Operator operator;        
}

Наконец, мы определяемAddRuleкласс, это только вдобавлятьИспользуемая операция:

public class AddRule implements Rule {
    @Override
    public boolean evaluate(Expression expression) {
        boolean evalResult = false;
        if (expression.getOperator() == Operator.ADD) {
            this.result = expression.getX() + expression.getY();
            evalResult = true;
        }
        return evalResult;
    }    
}

Теперь мы можем использоватьExpressionзвонитьRuleEngineв настоящее время:

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

4. Резюме

В этом руководстве мы рассмотрели ряд различных способов упростить сложный код. В то же время мы также узнали, как использовать эффективные шаблоны проектирования для замены сложных вложенных объявлений fi.

Как всегда, читатели могутрепозиторий githubПолучите полный исходный код.

Увидимся в следующий раз.

5. Резюме переводчика

Предположительно, все были более или менее обеспокоены этим бесконечным оператором if.В этой статье автор представляет 4 метода замены исходной структуры if с высокими затратами на обслуживание.Я надеюсь увидеть структуру после прочтения идеи дизайна полезны и избежать if ад, который делает других несчастными.


Маленькие динамики

Команда разработчиков Java компании Guangzhou Reed Technology

Reed Technology-Guangzhou Professional Internet Software Service Company

Ухватитесь за каждую деталь и создайте каждую красоту

Подпишитесь на наш официальный аккаунт, чтобы узнать больше

Хотите сразиться с нами? лагу поиск"Рид Технология» или отправить свое резюме наserver@talkmoney.cnПрисоединяйтесь к нам

Следите за нами, ваши комментарии и лайки - наша самая большая поддержка