Крупные операторы Switch: Bad OOP?

Я всегда считал, что крупные заявления о переключении являются симптомом плохого дизайна ООП. Раньше я читал статьи, в которых обсуждался этот вопрос, и они предоставили альтернирующие подходы на основе ООП, как правило, на основе polymorphismа, чтобы создать экземпляр правильного объекта для обработки дела.

Я сейчас в ситуации, у которой есть чудовищный оператор switch, основанный на streamе данных из сокета TCP, в котором протокол состоит из команды с завершающей командой новой строки, за которой следуют строки данных, за которыми следует конечный маркер. Команда может быть одной из 100 различных команд, поэтому я хотел бы найти способ уменьшить этот оператор переключения монстров на что-то более управляемое.

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

Существуют ли какие-либо шаблоны для такого рода проблем? Любые предложения о возможных реализациях?

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

Однако это также имеет проблему взрыва типа. Теперь мне нужно 100 новых classов, плюс мне нужно найти способ их чистое взаимодействие с моделью данных. Действительно ли «одно истинное предложение switch» действительно подходит?

Буду признателен за ваши мысли, мнения или комментарии.

Вы можете получить какую-то выгоду из командной строки .

Для ООП вы можете свернуть несколько похожих команд каждый в один class, если изменения поведения достаточно малы, чтобы избежать полного взрыва classа (да, я могу слышать, что гуру ООП визжат об этом уже). Однако, если система уже является ООП, и каждая из 100+ команд действительно уникальна, просто сделайте их уникальными classами и воспользуйтесь наследованием, чтобы консолидировать общий материал.

Если система не является ООП, то я бы не добавил OOP только для этого … вы можете легко использовать Command Pattern с простым поиском словаря и указателями функций или даже динамически сгенерированными вызовами функций на основе имени команды, в зависимости от язык. Затем вы можете просто группировать логически связанные функции в библиотеки, которые представляют собой набор похожих команд для достижения управляемой разметки. Я не знаю, есть ли хороший термин для такого рода реализации … Я всегда думаю об этом как о стиле «диспетчера», основанном на MVC-подходе к обработке URL-адресов.

Я вижу наличие двух операторов switch в качестве симптома дизайна без OO, где тип switch-on-enum может быть заменен несколькими типами, которые предоставляют различные реализации абстрактного интерфейса; например, следующее …

switch (eFoo) { case Foo.This: eatThis(); break; case Foo.That: eatThat(); break; } switch (eFoo) { case Foo.This: drinkThis(); break; case Foo.That: drinkThat(); break; } 

… возможно, следует переписать как …

 IAbstract { void eat(); void drink(); } class This : IAbstract { void eat() { ... } void drink() { ... } } class That : IAbstract { void eat() { ... } void drink() { ... } } 

Однако один оператор switch не является таким сильным индикатором, что оператор switch должен быть заменен чем-то другим.

Команда может быть одной из 100 различных команд

Если вам нужно сделать одну из 100 разных вещей, вы не можете избежать использования 100-way-ветви. Вы можете закодировать его в streamе управления (switch, if-elseif ^ 100) или в данных (100-элементная карта из строки в команду / factory / strategy). Но он будет там.

Вы можете попытаться изолировать результат 100-way branch от вещей, которые не должны знать этот результат. Может быть, всего 100 различных методов в порядке; нет необходимости изобретать объекты, которые вам не нужны, если это делает код громоздким.

Я думаю, что это один из немногих случаев, когда большие переключатели являются лучшим ответом, если не представлено какое-либо другое решение.

Я вижу страtagsю. Если у меня будет 100 различных страtagsй … пусть будет так. Операция гигантского переключателя является уродливой. Все ли действующие classные имена? Если это так, просто используйте имена команд как имена classов и создайте объект страtagsи с помощью Activator.CreateInstance.

Есть две вещи, которые приходят на ум, когда речь идет о большой инструкции switch:

  1. Это нарушает OCP – вы можете постоянно поддерживать большую функцию.
  2. У вас может быть плохая производительность: O (n).

С другой стороны, реализация карты может соответствовать OCP и может выполняться с потенциально O (1).

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

Я испытал это в одном проекте сам, когда все больше и больше кода переходило в коммутатор, пока оно не стало недостижимым. Моим решением было определить class параметров, содержащий контекст для команд (имя, параметры, все, что было собрано перед коммутатором), создать метод для каждого оператора case и вызвать этот метод с объектом параметра из этого случая.

Конечно, диспетчер команд с полным ООП (основанный на магии, такой как reflection или механизмы, такие как активация Java) более красив, но иногда вы просто хотите исправить ситуацию и получить работу;)

Вы можете использовать словарь (или хеш-карту, если вы кодируете на Java) (это называется табличной разработкой Стив Макконнелл).

Один из способов, по которым я вижу, что вы могли бы улучшить это, заставит ваш код управлять данными, так что, например, для каждого кода вы соответствуете тому, что его обрабатывает (функция, объект). Вы также можете использовать reflection для отображения строк, представляющих объекты / функции, и разрешать их во время выполнения, но вы можете сделать некоторые эксперименты для оценки производительности.

Лучший способ справиться с этой конкретной проблемой: чистое сериализация и протоколы – использовать IDL и генерировать код маршалинга с операторами switch. Поскольку любые шаблоны (прототип фабрики, командный шаблон и т. Д.) Вы пытаетесь использовать иначе, вам нужно будет инициализировать сопоставление между идентификатором / строкой команды и указателем classа / функции, так или иначе, и он будет работать медленнее, чем операторы switch, поскольку компилятор может использовать идеальный поиск hashа для операторов switch.

Да, я считаю, что заявления о больших случаях являются симптомом, что код может быть улучшен … обычно путем внедрения более объектно-ориентированного подхода. Например, если я сам оцениваю тип classов в инструкции switch, это почти всегда означает, что я, вероятно, мог бы использовать Generics для исключения оператора switch.

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

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

У меня недавно была аналогичная проблема с огромным оператором switch, и я избавился от уродливого коммутатора самым простым решением таблицы Lookup, а функция или метод вернули ожидаемое значение. Я думаю, что шаблон команды – хорошее решение, но, по-моему, 100 classов не очень приятны. поэтому у меня было что-то вроде:

 switch(id) case 1: DoSomething(url_1) break; case 2: DoSomething(url_2) break; .. .. case 100 DoSomething(url_100) break; 

и я изменился для:

 string url = GetUrl(id); DoSomthing(url); 

GetUrl может перейти в БД и вернуть URL-адрес, который вы ищете, или может быть словарь в памяти, содержащий 100 URL-адресов. Я надеюсь, что это может помочь кому-то там, заменяя огромные чудовищные инструкции switch.

Подумайте, как Windows была первоначально написана в насосе сообщений приложения. Он сосал. Приложения будут работать медленнее с добавлением дополнительных опций меню. По мере того как искомая команда заканчивалась все дальше и дальше в нижней части оператора switch, все больше ожидалось отклика. Недопустимо иметь длинные инструкции switch, период. Я сделал демон AIX как обработчик команд POS, который мог обрабатывать 256 уникальных команд, даже не зная, что было в streamе запросов, полученном по TCP / IP. Самым первым символом streamа был индекс в массив функций. Любой используемый индекс не был установлен для обработчика сообщений по умолчанию; журнал и попрощаться.

  • Статические и нестатические члены classа
  • Изучение / реализация шаблонов проектирования (для новичков)
  • Цепочка метода - почему это хорошая практика или нет?
  • Доступ к частному полю другого объекта в том же classе
  • В чем смысл сеттеров и геттеров в java?
  • Эквивалент C ++ экземпляра
  • Как создать статический class в C ++?
  • Полиморфизм - определение только двух предложений
  • Шаблоны проектирования доступа к данным
  • Почему открытые поля быстрее, чем свойства?
  • Заявления операторов плохие?
  • Interesting Posts

    Многие компьютеры, 1 комплект наушников. Каковы варианты?

    Когда использовать RAM-диск?

    Почему мы не можем читать один символ за раз из System.in?

    Использование CreateSourceQuery в CTP4 Code First

    Мой интернет-провайдер заблокировал меня из моего маршрутизатора

    Изображение панорамы и масштабирования

    Это плохая практика, чтобы поймать Throwable?

    Угловые директивы – когда и как использовать компиляцию, controller, предварительную ссылку и пост-ссылку

    Замена Java Regex с помощью группы захвата

    C ++ / Win32: Как дождаться завершения отложенного удаления?

    Почему плохо редактировать файл UIMap.designer.cs в тесте Visual Code UI?

    Окна 7 случайным образом закрываются. Где найти соответствующий журнал? Так что я могу определить ошибку

    Каковы различные настройки «Создание действия» в свойствах проекта Visual Studio и что они делают?

    Как определить поворот экрана

    Что делает оператор запятой?

    Давайте будем гением компьютера.