java чем заменить 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 с помощью эффективных шаблонов проектирования.

Источник

Замена switch-case полиморфизмом

Уважаемые участники форума!

В прекрасной книге «Философия С++» Брюса Эккеля я прочитал рекомендацию о том, что не следует использовать длинные switch-case конструкции. Вместо этого нужно применять полиморфизм и наследование. Вот убейте меня на месте, но я не пойму, как одно можно заменить другим!
Что такое switch-case конструкция? Это реализация выбора некоторого кода (из имеющегося списка) в соответствии с некоторым однозначно интерпретируемым критерием. Когда мы имеем дело с полиморфными вызовами функций классов наследников, используя при этом общий интерфейс (то есть класс-родитель), то здесь тоже наблюдается идея выбора кода (например, переопределенной функции) из некоторого множества. Но ведь в switch-case конструкции критерием является значение некоторой переменной (так чаще всего), а в случае с полиморфизмом критерием является тип!
Может быть, я, будучи новичком в С++, чего-то просто не понимаю? Не могли бы вы привести хотя бы примитивные примеры, как можно заменить первое вторым. Буду очень признателен.

14 ответов

[LEFT]Если честно, то не заменял. Но мне достаточно доступного интерфейса класса, защищённых членов класса, Friend’ ов связанных списков, полиморфных вызовов функций, компоновки всей этой каши в одно целое и т.д. и т.п. 😀
Я вобще очень редко (если опять таки честно) применяю конструкции case, считаю что возможно обойтись и без них, думаю эта конструкция хоть и используется в С++, но всё же(это моё мнение) она изжила себя и просто мигрировала из С))))
Я больше как-то использую Java. хм. и сами подумайте..ведь в Java как-то люди обходятся без case))))

Читайте также:  какой наполнитель нужен для котят

=)))))))))))
Ты что этим хотел сказать, что в Java нет конструкции switch/case абсолютно такой же как и в C/C++?

Я лично хотел сказать что она нафиг не нужна, вот и всё (это чисто по Русски)))). Блин, aks не придерайся к словам, а.
Или ты видел код на Java перенасыщенный конструкциями switch/case.
Продемонстрируй плиз))))) Очень хочу поглядеть 🙂
[/LEFT]

Не перенасыщенный, но активно применяющийся в случае необходимости видел неоднократно. Корпоративный закрытый код я конечно демонстрировать не буду, сам понимаешь наверно почему. Но полно опенсорсных проектов на яве. Глянь. Вот ссылка например: http://www.osflash.org/red5
=))

Интересный пример. чтоб показать один из вариантов замены switch/case полиморфизмом. 🙂

При небольшом количестве вариантов пакетов и нерасширяемой архитектуре switch/case будет вполне нормальным решением.
Но для других случаев больше подойдет архитектура с регистрацией обработчиков (псевдокод):

class IPacketHandler
<
TypeID getID() const =0;
TypeResult handlePacket(cont Packet&) =0;
>;

class DataPacketHandler :IPacketHandler
<
TypeID getID() const < return dataPacketID; >
TypeResult handlePacket(cont Packet&);
>;

class CommandPacketHandler :IPacketHandler
<
TypeID getID() const < return commandPacketID; >
TypeResult handlePacket(cont Packet&);
>;

class PacketManager
<
void addPacketHandler(IPacketHandler* handler) <
handlers.add(handler);
>

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

Ну и расширяемая вешь получается. Можно объединять несколько методов в одном таком классе-обработчике, например, предобработка и пост обработка (я недавно выкладывал HookAPI, там это явно прослеживается), можно хранить состояние обработчика и т.д. Представляется возможность получать информацию об обработчиках, настраивать их. Это нужно для более интеллектуальных менеджеров, например, кодеки: каждый кодек не только обрабатывает поток входных данных, но может и давать информацию о себе об формате входных и выходных данных. Это нужно, к примеру, для построения графов таких кодеков (см. DirectShow и GraphEdit).

В принципе вопрос из серии: что лучше callback-функция или объект-обработчик?

Источник

Простой способ облагородить свой код

Конечно же, это абстрактный пример, вырванный из контекста реального приложения. Только представьте себе, как мы выполняем вызовы функций внутри операторов. Или проверяем большое количество условий.

Каким решением разработчики пользуются чаще?

А сможете сразу понять, что не так с этим примером?

Написав такое, вы ничуть не сократите детализацию кода. Да и сложность кода никуда не денется. Такой код по-прежнему странно выглядит и с трудом поддерживается. Хотя теперь легче понять, что же вы пытаетесь в нем сделать.

Решение

Думаю, вам должно быть интересно, как работает рефакторинг. И почему этот пример может быть поучительным. Большинство людей привыкло писать код в такой хронологии:

Последняя часть обычно считается рефакторингом. И она не должна быть «разовой акцией». Не проводите рефакторинг впопыхах сразу после написания кода, чтобы затем позабыть о файле.

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

“Код должен быть гибким. И вы поддерживаете эту гибкость своим непрерывным вниманием к деталям ”.

Поэтому постарайтесь еще глубже погрузиться в процесс рефакторинга. Не останавливайтесь на первом этапе. А если работаете с уже готовым кодом, то пытайтесь улучшить его сразу. Плавно и без лишней спешки.

Проще, красивее и легче поддерживается. Это как раз то, что может сделать хороший рефакторинг. Но не останавливайтесь после первой попытки.

Читайте также:  при какой температуре выпекать бисквит в мультиварке редмонд

И помните, что вы можете пользоваться Map :

Заключение

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

Источник

Конструкции выбора в языке Java: if…else, switch

Вложенные условные операторы

Когда требуется последовательно перепроверять несколько взаимоисключающих условий, для частей else не открывают отдельного блока (записывают следующий if как простую, а не как составную инструкцию), чтобы получить более компактную запись. Такие конструкции в коде называют else…if.

Рассмотрим сначала вариант записи со вложенными блоками. Для примера рассмотрим следующую задачу.

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

Предположим, что возраст сохранён в переменной n, тогда для вывода подсказки потребуется следующий код:

Обратите внимание на то, что как только одно из условий окажется истинным — все последующие проверки не будут выполняться (т.е. в лучшем случае выполниться только первая проверка). Соответственно, сообщение об ошибке будет выведено тогда и только тогда, когда все проверяемые условия дадут ложный результат.

Более того, для сообщения о непризывном возрасте условие подобрано с учётом того, что заполняющий анкету уже не подошёл ни к одному из вариантов призывного возраста. Конечно, можно было бы использовать вот такое условие:

Но оно было бы избыточным, ведь ранее (за счёт выше стоящих проверок) мы уже убедились, что переменная n не попала в промежуток [18;60). Если бы переменная попадала в промежуток, то вывелось бы сообщение «Вы можете пройти срочную или контрактную службу» или «Вы можете служить только по контракту».

Но для случая, когда проверяется последовательность условий можно (но не необходимо) использовать более компактную запись, где содержание каждого else кроме последнего не оформляется в виде отдельного блока. Тот же фрагмент кода с учётом этой возможности может записываться так:

Оператор множественного выбора

Инструкция множественного выбора switch позволяет выполнять различные части программы в зависимости от того, какое значение будет иметь некоторая целочисленная переменной (её называют «переменной-переключателем», а «switch» с английского переводится как раз как «переключатель»).

Схема инструкции такова:

Рассмотрим все элементы оператора:

Рассмотрим такую ситуацию: в какой-то момент требуется просить у пользователя, надо ли продолжать программу или можно её завершить. Предположим, что ответ пользователя принимается в виде символа, вводимого с клавиатуры и сохраняемого в переменной ans: Д — да, продолжать, Н — нет, остановить.

Тогда получаем примерно такой программный код:

Если мы захотим как-то оповестить пользователя о том, что он ввёл неподходящий символ, то пригодится метка default:

Источник

Эстетическая красота: Switch vs If

Вводная

Немного нюансов

Речь ниже пойдет о сравнении оператора switch и его конкретной реализаций на языке Java и операторами if в виде оппонентов этой конструкции. О том, что у оператора switch имеется туз в рукаве — производительность (за редким исключением), пожалуй, знает каждый и этот момент рассматриваться не будет — так как крыть его нечем. Но все же, что не так?

1. Многословность и громоздкость

Среди причин, отталкивающих меня от использования оператора switch — это многословность и громоздкость самой конструкции, только взгляните — switch, case, break и default, причем опускаю за скобки, что между ними, наверняка, еще встретится return и throw. Не подумайте, что призываю не использовать служебные слова языка java или избегать их большого количества в коде, нет, лишь считаю, что простые вещи не должны быть многословными. Вот небольшой пример того, о чем говорю:

Читайте также:  ректороманоскопия на какую глубину

Итого для меня: switch/case/default VS if.

Если спросить, кому какой нравится больше код, то большинство отдаст предпочтение 1ому варианту, в то время как по мне, он — многословный. Речь о рефакторинге кода здесь не идет, все мы знаем, что можно было бы использовать константу типа EnumMap или IdentityHashMap для поиска списка по ключу channel или вообще убрать нужные данные в сам Channel, хотя это решение дискуссионное. Но вернемся.

2. Отступы

Возможно в академических примерах использование оператора swicth — это единственная часть кода, но тот код, с которым приходится сталкиваться, поддерживать — это более сложный, обросший проверками, хаками, где-то просто предметной сложностью код. И лично меня, каждый отступ в таком месте напрягает. Обратимся к ‘живому’ примеру (убрал лишнее, но суть осталась).

Итого для меня: 5 отступов VS 2.

Но опять, кому какой нравится вариант? Большинство отдаст предпочтение getReference1.
Отдельно стоит отметить, что количество отступов еще зависит от выбранного стиля форматирования кода.

3. Проверка на null

Если используется оператор switch со строками или енумами параметр выбора необходимо проверять на null. Вернемся к getTypes примерам.

Итого для меня: лишний код.

Даже если Вы абсолютно уверенны сейчас в том, что null ‘не придет’, это абсолютно не значит, что так будет всегда. Я проанализировал корпоративный багтрэк и нашел этому утверждению подтверждение. Справедливости ради стоит отметить, что структура кода выраженная через if не лишена этой проблемы, зачастую константы для сравнения используются справа, а не слева, например, name.equals(«John»), вместо «John».equals(name). Но в рамках данной статьи, по этому пункту, хотел сказать, что при прочих равных, подход со switch раздувается проверкой на null, при if же проверка не нужна. Добавлю еще, что статические анализаторы кода легко справляются с возможными null-багами.

4. Разношерстность

Очень часто, при длительном сопровождении кода, кодовая база раздувается и можно легко встретить код, похожий на следующий:

Итого для меня: разный стиль.

Раньше был ‘чистенький’ switch, а теперь switch + if. Происходит, как я называю, смешение стилей, часть кода ‘выбора’ выражена через switch, часть через if. Разумеется никто не запрещает использовать if и switch вместе, если это не касается операции выбора/под выбора, как в приведенном примере.

5. Чей break?

При использовании оператора switch, в case блоках может появиться цикл или на оборот, в цикле — switch, со своими прерываниями процесса обработки. Вопрос, чей break, господа?

Итого для меня: читаемость кода понижается.

Если честно, встречались и куда более запутанные примеры кода.

6. Неуместность

В java 7 появилась возможность использовать оператор switch со строками. Когда наша компания перешла на java 7 — это был настоящий Switch-Бум. Может по этому, а может и по другой причине, но во многих проектах встречаются похожие заготовки:

Итого для меня: появляются неуместные конструкции.

7. Гламурный switch под аккомпанемент хардкода

Немного юмора не помешает.

Заключение

Я не призываю Вас отказываться от оператора switch, местами он действительно хорош собой и лапша из if/if-else/else та еще каша. Но черезмерное его использование где ни попадя, может вызывать недовольство у других разработчиков. И я один из них.

Отдельно хотелось отметить, что c точки зрения понимания кода, у меня нет никаких проблем с switch/case — смысл написанного ясен, но вот с точки зрения восприятия эстетической красоты — есть.

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

Источник

Сказочный портал