3 мощные техники кодирования для удаления запутанных условных операторов
Представлены три мощные техники кодирования для оптимизации и упрощения сложных условных структур, улучшения качества и поддерживаемости кода.
В разработке программного обеспечения мы часто сталкиваемся с логикой кода, которая должна обрабатывать множество сценариев. Если не управлять должным образом, эта логика может легко превратиться в длинные цепочки if-else или массивные операторы switch. В этой статье будут представлены несколько эффективных методов оптимизации этих структур, что позволит улучшить качество кода и его поддерживаемость.
1. Защитное программирование: ранний возврат
Предположим, мы разрабатываем систему аутентификации пользователей, которая должна проверять различные статусы пользователей перед предоставлением доступа:
Этот код имеет очевидные структурные проблемы. Используются глубоко вложенные структуры if-else, что делает код трудным для чтения и поддержания. По мере увеличения числа проверок условий, уровень отступов кода увеличивается, формируя так называемый "стрелочный" код. Логика обработки ошибок разбросана по разным уровням вложенности, что не способствует их унифицированному управлению. Более важно, что основная логика кода—случай, когда доступ разрешен—погружена глубоко в многоуровневые условные суждения и лишена интуитивности. Этот стиль кодирования не только снижает читаемость кода, но и увеличивает риск ошибок и затрудняет расширение кода.
Мы можем оптимизировать этот код, используя подход "раннего возврата":
С помощью стратегии "раннего возврата" мы успешно оптимизировали исходную структуру кода.
Этот метод обеспечивает несколько улучшений:
- Он значительно уменьшает сложность вложенности кода. Каждая проверка условия обрабатывается независимо, делая общую логику более ясной и понятной. Эта упрощенная структура не только улучшает читаемость кода, но и значительно снижает сложность его обслуживания.
- Этот метод оптимизации достигает централизованного управления логикой обработки ошибок. Путем немедленного возврата результатов после каждой проверки условия мы избегаем ненужного выполнения кода, одновременно централизуя обработку различных сценариев ошибок, делая весь процесс обработки ошибок более организованным.
- Основная логика кода—условия для разрешения доступа—становится более заметной. Эта структура делает основную цель кода сразу очевидной, значительно увеличивая выразительность и понятность кода.
2. Метод таблицы поиска
Мы часто сталкиваемся со сценариями, в которых необходимо вернуть разные результаты на основе разных входных данных. Если не управлять должным образом, эти логики могут легко превратиться в длинные цепочки if-else или массивные операторы switch. Например, на платформе электронной коммерции нам необходимо возвращать соответствующие описания статусов на основе различных статусов заказов:
Это типичный сценарий возврата различных результатов на основе разных случаев. По мере увеличения числа случаев оператор switch или if-else суждения становятся длинными. Кроме того, в этом сценарии, если пользователям нужно перевести эт и статусы на другие языки, это потребует изменения тела функции или добавления новых функций, что приведет к значительным затратам на сопровождение.
В этом случае мы можем использовать метод таблицы поиска для оптимизации кода:
Во-первых, с помощью объекта Map для хранения соответствия между статусами и описаниями, код становится более лаконичным. Мы также сделали его легким для перемещения описаний статусов в файлы конфигурации, что обеспечивает удобство для интернационализации и динамических обновлений. При добавлении новых статусов, нам не нужно изменять основную логику кода; достаточно добавить соответствующие пары ключ-значение в конфигурацию.
3. Программирование, ориентированное на интерфейсы
При разработке больших программных систем, нам часто приходится поддерживать нескольких поставщиков услуг или функциональных модулей. Мы можем рассмотреть возможность использования программирования, ориентированного на интерфейсы, на стадии проектирования программного обеспечения, чтобы упростить последующие расширения, устраняя тем самым сложность множественных условных суждений, вызванных хардкодингом в сложных системах.
Предположим, мы разрабатываем многоязычную систему перевода, которая должна поддерживать различных поставщиков услуг перевода. Если не учитывать программирование, ориентированное на интерфейсы, на стадии проектирования, последующие расширения станут очень сложными:
Эта реализация использует простую и грубую структуру if-else для выбора поставщиков перевода, что делает код трудным для поддержания и расширения. При добавлении новых поставщиков перевода в будущем, существующий код придется изменять, и по мере увеличения числа поддерживаемых поставщиков перевода, код станет громоздким и трудным для сопровождения. В то же время, этот сложный метод также труден для юнит-тестирования, так как сложно сымитировать различных поставщиков перевода.
Для решения этих проблем, мы можем использовать программирование, ориентированное на интерфейсы, для оптимизации кода. Программирование, ориентированное на интерфейсы, является важным способом реализации полиморфизма, позволяя различным объектам по-разному реагировать на одно и то же сообщение.
Процесс реализации:
- Определите интерфейс стратегии перевода:
- Реализуйте этот интерфейс для каждого поставщика перевода:
- Переформатируйте класс TranslationService, передавая стратегию в качестве параметра:
- Используйте оптимизированный код:
Определив интерфейс TranslationStrategy
и введя программирование, ориентированное на интерфейсы, мы достигли следующих преимуществ:
TranslationService
может использовать различные стратегии перевода для каждого вызова.- Добавление новых поставщиков перевода становится простым, достаточно создать новый класс стратегии и реализовать интерфейс.
- Клиентский код может гибко выбирать стратегию для каждого перевода без изменения основной логики
TranslationService
. - К аждая стратегия перевода может быть протестирована независимо, улучшая тестируемость кода.
- Избежание поддержания состояния в
TranslationService
делает сервис более статeless и потокобезопасным.
Заключение
Оптимизация структур условных операторов является важным средством улучшения качества кода. Три метода, представленные в этой статье—защитное программирование, метод таблицы поиска и программирование, ориентированное на интерфейсы (в сочетании с полиморфизмом)—каждый имеет свои применимые сценарии:
- Защитное программирование подходит для обработки множества независимых проверок условий и может эффективно уменьшить вложенность кода.
- Метод таблицы поиска подходит для обработки требований, реагирующих по-разному на различные случаи, делая код более лаконичным и легким для сопровождения.
- Программирование, ориентированное на интерфейсы, в сочетании с полиморфизмом подходит для построения сложных, но гибких систем, улучшая гибкость и масштабируемость кода.
В реальной разработке нам часто нужно выбирать подходящие методы в зависимости от конкретных ситуаций, а иногда даже необходимо комплексно применять несколько техник. Главное—сбалансировать простоту, читаемость и поддерживаемость кода, выбирая решение, которое лучше всего соответствует текущей проблеме.
Помните, чрезмерная оптимизация может привести к излишне сложному коду. Сохранение кода простым и читаемым всегда остается основным принципом. При применении этих методов следует делать мудрый выбор, основываясь на конкретных потребностях проекта и техническом уровне команды.