Как можно исключить использование ключа в коде?
design-patterns
Mariano
источник
источник
Ответы:
Операторы switch сами по себе не являются антипаттернами, но если вы кодируете объектно-ориентированные, вы должны подумать, лучше ли использовать переключение с помощью полиморфизма, а не с помощью оператора switch.
С полиморфизмом это:
становится так:
источник
typeof
, и в этом ответе не предлагаются способы или причины обхода операторов switch в других ситуациях.См. Запах Заявлений Переключателя :
И Рефакторинг, и Рефакторинг на Шаблоны имеют подходы для решения этой проблемы.
Если ваш (псевдо) код выглядит так:
Этот код нарушает принцип Open Closed и является хрупким по отношению к каждому новому типу кода действия. Чтобы исправить это, вы можете ввести объект «Command»:
Если ваш (псевдо) код выглядит так:
Тогда вы можете ввести объект «State».
Надеюсь это поможет.
источник
Map<Integer, Command>
не нуждается в переключателе?Переключатель - это шаблон, независимо от того, реализован ли он с помощью оператора switch, цепочки, таблицы поиска, полиморфизма oop, сопоставления с шаблоном или чего-то еще.
Вы хотите исключить использование « оператора switch » или « шаблона switch »? Первый может быть исключен, второй, только если можно использовать другой шаблон / алгоритм, и большую часть времени это невозможно или это не лучший подход для этого.
Если вы хотите исключить оператор switch из кода, первый вопрос, который нужно задать, - это где имеет смысл исключить оператор switch и использовать какой-то другой метод. К сожалению, ответ на этот вопрос зависит от конкретной области.
И помните, что компиляторы могут выполнять различные оптимизации для переключения операторов. Например, если вы хотите эффективно обрабатывать сообщения, лучше всего использовать оператор switch. Но, с другой стороны, выполнение бизнес-правил, основанных на выражении switch, вероятно, не лучший способ, и приложение должно быть переосмыслено.
Вот несколько альтернатив для переключения оператора:
источник
Само по себе переключение не так уж и плохо, но если у вас в ваших методах много «switch» или «if / else» для объектов, это может быть признаком того, что ваш дизайн немного «процедурный» и что ваши объекты просто ценны ковши. Переместите логику в ваши объекты, вызовите метод для ваших объектов и дайте им решить, как реагировать.
источник
Я думаю, что лучший способ - использовать хорошую карту. Используя словарь, вы можете сопоставить практически любой вход с другим значением / объектом / функцией.
ваш код будет выглядеть примерно так (psuedo):
источник
Все любят огромные
if else
блоки. Так легко читать! Мне любопытно, почему вы хотели бы удалить операторы switch, хотя. Если вам нужен оператор switch, вам, вероятно, нужен оператор switch. Если серьезно, я бы сказал, что это зависит от того, что делает код. Если все, что делает переключатель - это вызывает функции (скажем), вы можете передавать указатели на функции. Является ли это лучше решение спорно.Язык также является важным фактором и здесь, я думаю.
источник
Я думаю, что вы ищете шаблон стратегии.
Это может быть реализовано несколькими способами, которые были упомянуты в других ответах на этот вопрос, таких как:
источник
switch
операторы было бы хорошо заменить, если вы обнаружите, что добавляете новые состояния или новое поведение в операторы:Добавление нового поведения требует копирования
switch
, а добавление новых состояний означает добавление другогоcase
в каждоеswitch
утверждение.В Java вы можете переключать только очень ограниченное количество примитивных типов, значения которых вы знаете во время выполнения. Это само по себе представляет проблему: состояния представляются в виде магических чисел или символов.
if - else
Можно использовать сопоставление с образцом и несколько блоков, хотя на самом деле возникают те же проблемы при добавлении нового поведения и новых состояний.Решение, которое другие предложили как «полиморфизм», является примером модели состояния :
Замените каждое из состояний своим собственным классом. Каждое поведение имеет свой метод в классе:
Каждый раз, когда вы добавляете новое состояние, вы должны добавить новую реализацию
IState
интерфейса. Вswitch
мире вы бы добавилиcase
к каждомуswitch
.Каждый раз, когда вы добавляете новое поведение, вам необходимо добавить новый метод в
IState
интерфейс и каждую из реализаций. Это то же бремя, что и раньше, хотя теперь компилятор будет проверять, есть ли у вас реализации нового поведения в каждом ранее существующем состоянии.Другие уже говорили, что это может быть слишком тяжеловесно, поэтому, конечно, есть момент, когда вы переходите от одного к другому. Лично, второй раз, когда я пишу переключатель, это точка, в которой я выполняю рефакторинг.
источник
если еще
Я опровергаю предположение, что по сути это плохо.
источник
Ну, во-первых, я не знал, что использование switch - это анти-паттерн.
Во-вторых, switch всегда можно заменить на операторы if / else if.
источник
Почему ты хочешь? В руках хорошего компилятора оператор switch может быть гораздо более эффективным, чем блоки if / else (а также более легким для чтения), и, скорее всего, ускорятся только самые большие переключатели, если они будут заменены каким-либо видом косвенной структуры данных поиска.
источник
«switch» - это просто языковая конструкция, и все языковые конструкции можно рассматривать как инструменты для выполнения работы. Как и в случае с реальными инструментами, некоторые инструменты лучше подходят для одной задачи, чем для другой (вы не использовали бы кувалду для подвешивания крючка для фото). Важной частью является то, как определяется «выполнение работы». Должен ли он быть обслуживаемым, быстрым, масштабируемым, расширяемым и т. Д.
В каждой точке процесса программирования обычно существует ряд конструкций и шаблонов, которые можно использовать: переключатель, последовательность if-else-if, виртуальные функции, таблицы переходов, карты с указателями функций и так далее. С опытом программист инстинктивно узнает, какой инструмент использовать в данной ситуации.
Следует предположить, что любой, кто поддерживает или просматривает код, по крайней мере так же квалифицирован, как и автор оригинала, так что любая конструкция может быть безопасно использована.
источник
Если есть переключатель, позволяющий различать различные типы объектов, вы, вероятно, упускаете некоторые классы для точного описания этих объектов или некоторые виртуальные методы ...
источник
Для C ++
Если вы имеете в виду, например, AbstractFactory, я думаю, что метод registerCreatorFunc (..) обычно лучше, чем требование добавлять регистр для каждого необходимого «нового» оператора. Затем позволяем всем классам создавать и регистрировать функцию creatorFunction (..), которая может быть легко реализована с помощью макроса (если я осмелюсь упомянуть). Я считаю, что это общий подход, который используют многие структуры. Я впервые увидел это в ET ++, и я думаю, что многие фреймворки, требующие макроса DECL и IMPL, используют его.
источник
В процедурном языке, таком как C, переключение будет лучше, чем любая из альтернатив.
В объектно-ориентированном языке почти всегда есть другие доступные альтернативы, которые лучше используют структуру объекта, особенно полиморфизм.
Проблема с операторами switch возникает, когда несколько очень похожих блоков переключателей появляются в нескольких местах приложения, и необходимо добавить поддержку нового значения. Разработчик довольно часто забывает добавить поддержку нового значения в один из блоков переключателей, разбросанных по всему приложению.
При полиморфизме новый класс заменяет новое значение, и новое поведение добавляется как часть добавления нового класса. Поведение в этих точках переключения затем либо наследуется от суперкласса, переопределяется для обеспечения нового поведения, либо реализуется во избежание ошибки компилятора, когда метод super является абстрактным.
Там, где не происходит явного полиморфизма, может быть целесообразно реализовать шаблон Стратегии .
Но если ваша альтернатива - это большой блок IF ... THEN ... ELSE, то забудьте об этом.
источник
Используйте язык, который не поставляется со встроенным оператором switch. Perl 5 приходит на ум.
Если серьезно, почему вы хотите избежать этого? И если у вас есть веские основания избегать этого, то почему бы просто не избежать этого?
источник
Указатели на функции - это один из способов заменить громоздкий оператор switch, они особенно хороши в языках, где вы можете захватывать функции по их именам и создавать что-то с ними.
Конечно, вы не должны принудительно выдавать операторы switch из своего кода, и всегда есть вероятность, что вы все делаете неправильно, что приводит к глупым избыточным частям кода. (Иногда это неизбежно, но хороший язык должен позволять вам удалять избыточность, оставаясь чистым.)
Это отличный пример «разделяй и властвуй»:
Скажем, у вас есть какой-то переводчик.
Вместо этого вы можете использовать это:
Обратите внимание, что я не знаю, как удалить избыточность opcode_table в C. Возможно, я должен задать вопрос об этом. :)
источник
Наиболее очевидный, независимый от языка ответ - использовать серию «если».
Если используемый вами язык имеет указатели на функции (C) или функции, которые являются значениями 1-го класса (Lua), вы можете добиться результатов, аналогичных «переключению», используя массив (или список) из (указателей) функций.
Вы должны быть более конкретными на языке, если вы хотите получить лучшие ответы.
источник
Операторы Switch часто могут быть заменены хорошим дизайном OO.
Например, у вас есть класс «Учетная запись», и вы используете оператор переключения для выполнения другого расчета в зависимости от типа учетной записи.
Я бы предложил заменить его на ряд классов учетных записей, представляющих различные типы учетных записей, и все они реализуют интерфейс учетной записи.
В этом случае переключение становится ненужным, поскольку вы можете обрабатывать все типы учетных записей одинаково, и благодаря полиморфизму будет выполнен соответствующий расчет для типа учетной записи.
источник
Зависит от того, почему вы хотите заменить его!
Многие интерпретаторы используют «вычисленные переходы» вместо операторов switch для выполнения кода операции.
Что мне не хватает в переключателе C / C ++, так это Pascal 'in' и диапазоны. Я также хотел бы включить струны. Но они, хотя и являются тривиальными для компилятора, являются тяжелой работой, когда они выполняются с использованием структур, итераторов и прочего. Так что, напротив, есть много вещей, которые я хотел бы заменить на переключатель, если бы только ключ C () был более гибким!
источник
Переключение не очень хороший способ, так как он нарушает принцип Open Close. Вот как я это делаю.
И вот как это использовать (принимая ваш код):
В основном то, что мы делаем, - делегирование ответственности дочернему классу вместо того, чтобы родитель решал, что делать с детьми.
Вы также можете прочитать «Принцип замещения Лискова».
источник
В JavaScript используется ассоциативный массив:
this:
становится так:
учтивость
источник
Еще один голос за если / еще. Я не большой поклонник дел или заявлений о смене, потому что есть люди, которые их не используют. Код менее читабелен, если вы используете регистр или переключатель. Может быть, не менее читабельным для вас, но для тех, кому никогда не нужно было использовать команду.
То же самое касается объектных фабрик.
Блоки if / else - это простая конструкция, которую получают все. Есть несколько вещей, которые вы можете сделать, чтобы убедиться, что у вас нет проблем.
Во-первых, не пытайтесь делать отступы, если утверждения более чем пару раз. Если вы обнаружите, что делаете отступы, значит, вы делаете это неправильно.
Это действительно плохо - делай это вместо этого.
Оптимизация будь проклята. Это не имеет большого значения для скорости вашего кода.
Во-вторых, я не против выхода из блока If, если в определенном блоке кода разбросано достаточно операторов break, чтобы сделать его очевидным
РЕДАКТИРОВАТЬ : On Switch и почему я думаю, что трудно уловить:
Вот пример оператора switch ...
Для меня проблема здесь в том, что нормальные управляющие структуры, которые применяются в C-подобных языках, были полностью нарушены. Существует общее правило, что если вы хотите поместить более одной строки кода в управляющую структуру, вы используете фигурные скобки или оператор начала / конца.
например
Для меня (и вы можете исправить меня, если я ошибаюсь), оператор Case выбрасывает это правило в окно. Условно исполняемый блок кода не помещается в структуру начала / конца. Из-за этого, я считаю, что Case концептуально отличается настолько, что его нельзя использовать.
Надеюсь, что отвечает на ваши вопросы.
источник