Прекратите использовать оператор If-else
Вы просмотрели бесчисленные учебные пособия, использующие операторы If-else. Вы, вероятно, также читали книги по программированию, пропагандирующие использование If-else в качестве фактического метода ветвления.
Возможно, это даже ваш режим по умолчанию, чтобы использовать If-else. Но давайте покончим с этим прямо сейчас, заменив If-else объектами состояния.
Обратите внимание, что этот подход можно использовать, если вы пишете класс с методами, которые нуждаются в изменении его реализаций в зависимости от текущего состояния. Вы бы применили другой подход, если бы не имели дело с изменяющимся состоянием объекта.
Даже если вы слышали о шаблоне состояния, вы можете задаться вопросом, как он реализован в готовом к продакшену коде.
Для тех, кто все еще находится в неведении, вот очень краткое введение.
Вы увеличите сложность с любым новым условным требованием, реализованным с помощью If-else.
Применяя шаблон состояния, вы просто изменяете поведение объектов, используя специализированные объекты состояния вместо операторов If-else.
Прошли те дни, когда код выглядел примерно так, как показано ниже.
Вы, конечно, писали более сложные ветвления раньше. Несколько лет назад я был уверен в этом.
Приведенная выше логика ветвления даже не очень сложна — но попробуйте добавить новые условия, и вы увидите, что она усложняется в разы.
Кроме того, если вы думаете, что создание новых классов вместо простого использования ветвящихся операторов звучит раздражающе, подождите, пока вы не увидите это в действии. Этот способ лаконичен и элегантен.
Даже лучше, это сделает вашу кодовую базу более SOLID, за исключением буквы ”D».
«Хорошо, я поверил, что if-else — это зло, теперь покажите мне, как избежать беспорядочного ветвящегося кода»
Мы рассмотрим, как я заменяю If-else в готовом к продакшену коде. Это выдуманный пример, но подход тот же, что я использовал в кодовых базах для крупных клиентов.
Я нарисовал диаграмму в меру своих возможностей, которая отображает различные состояния, в которых может находиться бронирование.
Рефакторинг ветвящейся логики из нашего кода представляет собой трехэтапный процесс:
Реализация
Во-первых, нам нужен класс базового состояния, который унаследуют все состояния.
Обратите внимание, что этот класс также имеет два метода, Accept и Cancel — хотя здесь они помечены как внутренние.
Во-вторых, мы создаем отдельные классы для каждого состояния, которое хотим представлять.
Обратите внимание, как каждый класс представляет состояние, описанное на красивой диаграмме выше. Кроме того, CancelledState не позволит нашему бронированию перейти в новое состояние. Этот класс очень похож по духу на шаблон нулевого объекта.
Наконец, сам класс бронирования.
Посмотрим, класс бронирования — это просто делегирование полномочий осуществления принятия и отклонения?
Это позволяет нам устранить большую часть условной логики и позволяет каждому состоянию сосредоточиться только на том, что важно для него самого — текущее состояние также имеет возможность перевести бронирование в новое состояние.
Как бороться с новыми условиями
Если новая функция обычно была реализована с помощью некоторой условной проверки, то теперь вы можете просто создать новый класс состояния.
Это очень просто. Вам больше не придется иметь дело с громоздким оператором if-else.
Как сохранить объект состояния в базе данных
Объект состояния не имеет значения при сохранении объекта, например, в базе данных SQL или NoSQL. Важно только знать состояние объекта и то, как оно должно быть отображено в столбце.
Вы можете сопоставить состояние с читаемым именем, перечислением или целым числом. Все, что вам удобно, пока у вас есть какой-то способ преобразовать сохраненное значение обратно в объект состояния.
Но ты все еще используешь «if»
Да, он очень важен. Особенно при использовании в качестве проверочных точек. Именно сочетание If-else является основной причиной головных болей поддержки кода.
Это же куча дополнительных классов
Действительно. Как я уже упоминал в другой статье, сложность возникает не из количества классов, которые у вас есть, а из обязанностей, которые эти классы берут на себя.
Наличие большого количества специализированных классов сделает ваш код более читаемым, поддерживаемым и просто более приятным для работы.
Узнайте подробности, как получить востребованную профессию с нуля или Level Up по навыкам и зарплате, пройдя платные онлайн-курсы SkillFactory:
Альтернатива if/else и switch: литералы объектов в JavaScript
Сложные условия в JS всегда были источником лишнего кода. Однако использование литералов объектов в JavaScript может избавить вас от этой проблемы. Давайте разберёмся, как это работает.
Литерал объекта в JavaScript — это список пар ключ-значение, перечисленных через запятую и обёрнутый фигурными скобками.
Допустим у нас есть функция, которая принимает на вход рифмованную фразу на английском сленге кокни и возвращает её значение. Если использовать конструкцию if/else, то код будет выглядеть следующим образом:
Выглядит так себе. Этот код не только плохо читается, но и использует повторяющийся вызов функции toLowerCase().
Чтобы уменьшить количество кода, мы можем использовать дополнительную переменную или конструкцию switch.
Такой код выглядит чище, но это не предел. К тому же, в случае использования более сложных условий, можно случайно пропустить break и спровоцировать баги.
Альтернатива
Мы можем достичь той же функциональности используя объект. Вот пример, который выглядит гораздо аккуратнее:
Мы используем объект, ключи которого выполняют роль условий, а значения — результатов. Затем, с помощью квадратных скобок, мы проверяем наличие нужной строки. Так как полученная строка может быть null или undefined, то мы используем оператор Nullish coalescing (??). Таким образом мы избавляемся от null-значения, но не исключаем случай, что результат может быть равен нулю или false.
Подробнее о способах обработки undefined в JavaScript.
Сложная логика
Для организации более сложных условий вы можете использовать в качестве значений свойств функции.
В этом коде мы выбираем необходимую функцию по ключу, а затем вызываем её с двумя аргументами. Так как мы используем опциональную цепочку, то функция вызовется только, если она существует. В противном случае вернётся дефолтное значение.
Вывод
Каждая условная конструкция имеет свою область применения. Для литералов объектов в JavaScript это длинные списки условий и сложные условия, которые можно реализовать с помощью функций.
Программное обеспечение без конструкции if-else
Не откладывая в долгий ящик скажу: зачастую конструкция if-else — плохой выбор. Её использование приводит к сложным конструкциям, снижает читаемость кода и усложняет рефакторинг.
Тем не менее, конструкция if-else де-факто стала решением для ветвления кода, что имеет смысл. Это одна из первых тем, которую изучают начинающие разработчики. К несчастью, многие так никогда и не переходят на более подходящие стратегии ветвления.
Некоторые живут по правилу: if-else молоток, всё остальное — гвозди.
Неспособность определить, когда использовать более подходящий инструмент, относится к числу признаков, отличающих начинающих и опытных разработчиков.
Я продемонстрирую несколько приёмов и шаблонов, которые помогут положить конец этой неприятной практике. Сложность будет возрастать с каждым примером.
1. Совсем лишние блоки else
Это самая распространённая ошибка начинающих разработчиков. Ниже яркий пример того, как вы проигрываете, используя if-else:
Выражение легко упростить, просто убрав блок else :
Выглядит более профессионально, не так ли?
Вы регулярно будете обнаруживать, что блок else вам совсем не нужен, как в примере выше, когда вам нужно сделать что-то при выполнении некоторого условия и немедленно получить результат.
2. Присвоение значений
Если вам нужно присвоить значение переменной на основе некоторого ввода, бросьте эту возню с if-else — существует намного более читаемый подход:
Убираем else if и else и получаем чистый читаемый код. Обратите внимание, что я изменил стиль быстрого возвращаемого значения — просто не имеет смысла проверять значение, когда верное уже получено.
3. Проверка входных условий
Чаще всего я обнаруживаю, что нет смысла продолжать выполнение метода, если он включает неверные значения.
Скажем, у нас есть вышеописанный метод DetermineGender с требованием, чтобы входное значение равнялось 0 или 1:
Выполнение метода без проверки значений не имеет смысла. Следовательно, нам нужно проверить входные условия перед выполнением метода.
Применив граничные операторы метода безопасного программирования, сначала проверяем входные значения и только потом выполняем метод if:
На этом этапе мы убедились, что основная логика выполняется, только если значения находятся в ожидаемом диапазоне.
Операторы if также заменены на тернарные, так как больше нет смысла возвращать значение “Unknown”.
4. Превращение if-else в словарь — полностью избегаем if-else
Скажем, нужно выполнить некоторую операцию, выбранную на основе некоторого условия, и заранее известно, что позднее нужно будет добавлять ещё операции:
Возможно, кто-то использует старый добрый if-else. Добавление новой операции — просто добавление ещё одного if. Всё просто. Однако с точки зрения производительности этот подход неэффективен.
Зная, что впоследствии нужно будет добавлять ещё операции, превратим if-else в словарь:
Читаемость выросла, код проще понять.
Обратите внимание, что словарь размещён внутри метода исключительно в целях демонстрации. Вам, скорее всего, захочется, чтобы он был предоставлен извне.
5. Расширение приложений — полностью избегаем if-else
Немного более продвинутый пример
Необходимо уточнить — это более “корпоративный” подход. Нетипичный сценарий “давайте заменим if-else”. Теперь можно продолжить.
If можно полностью заменить объектами.
Довольно часто необходимо расширить какую-то часть приложения. Как начинающий разработчик вы можете просто использовать дополнительный оператор if-else (или else-if).
Однако этот подход определённо не приемлем, если эту часть приложения нужно будет расширять.
Мало того, что код выше не соответствует принципу открытости/закрытости, его трудно читать и поддерживать в долгосрочной перспективе.
Правильный подход — подход, придерживающийся принципов SOLID— внедрение процесса обнаружения динамического типа, а в данном случае, стратегической модели.
Рефакторинг этого беспорядочного куска кода выглядит так:
Посмотрите на код, заменяющий пример выше. Да, здесь значительно больше кода, требуется знать, как работает обнаружение типов.
Но динамическое расширение приложений — сложная тема.
Я продемонстрировал только часть, заменяющую пример с if-else. Здесь можно увидеть все вовлечённые объекты.
В идеале обнаружение типов и словарь предоставляются снаружи метода PrintOrder. Но в любом случае давайте пробежимся по коду выше:
❗ Удалите из кода If-Else и Switch Case
Перевод публикуется с сокращениями, автор оригинальной статьи Nicklas Millard.
C корее всего, i f- e lse и switch – ваш обычный подход к ветвлению кода, но в нем нет необходимости. Вы можете полностью исключить ключевое слово else из своего словаря по программированию. Некоторые матерые кодеры говорят, что i f-else – полиморфизм новичков.
Что плохого в традиционном ветвлении?
Много чего. Традиционное ветвление быстро разрастается. Вам придется изменять существующий код каждый раз при добавлении новой функции. Это нарушает принцип Open-Closed. Функции должны быть реализованы с помощью новых классов.
Какие есть альтернативы?
Существует масса альтернатив, но мы рассмотрим три типовых подхода, которые часто применяются при удалении традиционного ветвления из кода:
Эти 3 подхода легко справятся с большинством повседневных ситуаций, с которыми вы можете столкнуться.
Все методы имеют общие черты:
Моделирование концепций с помощью простых классов
Допустим, у нас есть класс User и в нем имя пользователя. Оно является строкой и имеет два условия: не может быть нулем или пустой строкой и не может превышать 50 символов.
Можно с уверенностью предположить, что нам понадобятся имена пользователей в других частях приложения. Каждый раз, когда мы получаем имя, придется выполнять одни и те же проверки, которые будут разбросаны по всему проекту.
Гораздо лучшим подходом является перенос концепции имени пользователя и создание небольшого специализированного объекта, как показано ниже.
Этот фрагмент кода, несомненно, чище. Теперь каждый раз, когда потребуется обновление, его нужно будет делать только в одном месте.
Изменение реализации метода объекта в зависимости от его состояния
Иногда необходимо, чтобы объект вел себя по-разному в зависимости от его внутреннего состояния. Типичный ленивый способ реализации этого – традиционное ветвление, как в приведенном ниже примере.
Всякий раз, когда нам нужно вывести деньги, в аккаунте следует проверить внутреннее состояние и вести себя соответственно.
Паттерн состояния – это очень крутой подход к удалению сумасшедшей вложенной условной логики. Пытайтесь добиться, чтобы наш код был похож на следующий:
Видите, какая плоская конструкция?
Удвойте количество кода и повысьте читабельность.
У нас есть базовый класс, от которого наследуется каждый объект состояния. Если мы получим новый запрос на добавление состояния RequiresValidation или что-то еще, будет легко реализовать эту функцию, не касаясь существующих классов.
Внимательный читатель заметил, что нет никакого перехода в состояние. Очевидно, что классы не полностью реализованы, т. к. переход из одного состояния в другое выходит за рамки статьи.
Рефакторинг ветвлений на отдельные классы
Наиболее часто используемый способ устранения условных ветвлений – объекты стратегии.
Предположим, что класс живет в какой-то общей библиотеке, от которой зависит много проектов в вашей организации. Если одной команде нужен новый вариант преобразования, ей придется обратиться к сопровождающим проекта, чтобы они добавили функциональность, создали новую версию и опубликовали ее.
Мы можем сделать это, разделив каждую ветку switch/case на специализированные классы, что делает enum ненужным.
Рассмотрим приведенный ниже код:
Чтобы это сработало, необходимо определить некоторые ограничения: любой форматер должен реализовать IValueFormatter и иметь конструктор по умолчанию.
Представьте, как легко сейчас протестировать и исправить ошибки. Вы всегда будете точно знать, что проверять и где искать. Больше никаких следов безумной switch-логики.
Заключение
К сожалению, традиционное ветвление используется очень широко. Многие разработчики придерживаются своего испытанного и верного способа ветвления кода, не осознавая, что обслуживание и добавление функциональности превратилось в кошмар.
Как заменить многие операторы if в Java
Изучите различные способы замены сложных вложенных операторов if
1. Обзор
Конструкции принятия решений являются жизненно важной частью любого языка программирования. Но мы попадаем в кодирование огромного количества вложенных операторов if, которые делают наш код более сложным и трудным в обслуживании.
Давайте рассмотрим различные варианты того, как мы можем упростить код.
2. Тематическое исследование
Мы также можем реализовать это с помощью switch statements :
Еще одним побочным эффектом вложенных конструкций решений является то, что они становятся неуправляемыми. Например, если нам нужно добавить новый оператор, мы должны добавить новый оператор if и реализовать операцию.
3. Рефакторинг
Давайте рассмотрим альтернативные варианты замены сложных операторов if выше на гораздо более простой и управляемый код.
3.1. Заводской класс
Метод принимает два числа в качестве входных данных и возвращает результат. Давайте определим класс для выполнения дополнений:
Теперь мы реализуем фабричный класс, который возвращает экземпляры Operation на основе данного оператора:
Теперь в классе Calculator мы можем запросить завод, чтобы получить соответствующую операцию и применить исходные номера:
В этом примере мы видели, как ответственность делегируется слабо связанным объектам, обслуживаемым фабричным классом. Но могут быть шансы, что вложенные операторы if просто будут перенесены в класс factory, что противоречит нашей цели.
3.2. Использование перечислений
Давайте посмотрим, как мы можем этого достичь. Сначала нам нужно определить наше Перечисление :
Мы определим методы для каждого из значений Enum и выполним расчет. Например:
А затем в классе Calculator мы можем определить метод для выполнения операции:
Теперь мы можем вызвать метод путем преобразования String значения в Оператор с помощью Operator#valueOf() метод :
3.3. Шаблон команд
Сначала мы определим наш Командный интерфейс:
Далее, давайте реализуем команду Add:
Затем мы можем вызвать вычисление, создав экземпляр команды Add и отправив ее в метод Calculator#calculate :
3.4. Механизм правил
Когда мы в конечном итоге пишем большое количество вложенных операторов if, каждое из условий отображает бизнес-правило, которое должно быть оценено для правильной обработки логики. Механизм правил выводит такую сложность из основного кода. Механизм Правил оценивает Правила и возвращает результат на основе входных данных.
Во-вторых, давайте реализуем Механизм правил :
Теперь мы вызовем механизм правил с выражением |:
4. Заключение
В этом уроке мы рассмотрели ряд различных вариантов упрощения сложного кода. Мы также узнали, как заменить вложенные операторы if с помощью эффективных шаблонов проектирования.


















