Мне дали посмотреть на Java-код, который имитирует гонку автомобиля, включая реализацию базового автомата. Это не классическая машина состояний компьютерных наук, а просто объект, который может иметь несколько состояний и может переключаться между его состояниями на основе серии вычислений.
Чтобы описать только проблему, у меня есть класс Car с вложенным классом enum, который определяет некоторые константы для состояния Car (например, OFF, IDLE, DRIVE, REVERSE и т. Д.). В этом же классе автомобилей у меня есть функция обновления, которая в основном состоит из большого оператора switch, который включает текущее состояние автомобилей, выполняет некоторые вычисления и затем изменяет состояние автомобилей.
Насколько я вижу, состояние Cars используется только в своем классе.
Мой вопрос заключается в том, является ли это лучшим способом реализации конечного автомата природы, описанного выше? Это звучит как наиболее очевидное решение, но в прошлом я всегда слышал, что «операторы переключения плохие».
Основная проблема, которую я вижу здесь, заключается в том, что оператор switch может стать очень большим, если мы добавим больше состояний (если это будет сочтено необходимым), а код станет громоздким и сложным в обслуживании.
Что было бы лучшим решением этой проблемы?
источник
object.state = object.function(object.state);
Ответы:
Я превратил Автомобиль в своего рода конечный автомат, используя State Pattern . Notice no
switch
илиif-then-else
операторы используются для выбора состояния.В этом случае все состояния являются внутренними классами, но это может быть реализовано иначе.
Каждое состояние содержит действительные состояния, на которые оно может измениться.
Пользователю предлагается указать следующее состояние, если возможно более одного, или просто подтвердить, если возможно только одно.
Вы можете скомпилировать и запустить его для проверки.
Я использовал графическое диалоговое окно, потому что таким способом было проще запустить его в Eclipse.
Диаграмма UML взята отсюда .
источник
Именно такое упрощение дает плохое имя объектно-ориентированному программированию. Использование
if
так же «плохо», как использование оператора switch. В любом случае вы не полиморфно отправляете.Если у вас должно быть правило, подходящее под звуки, попробуйте следующее:
Оператор switch, который не дублируется нигде в базе кода, иногда может не быть злым. Если дела не являются публичными, но заключены в капсулу, это действительно ничто другое. Особенно, если вы знаете, как и когда проводить рефакторинг в классах. То, что ты можешь, не означает, что ты должен. Это потому, что вы можете сделать это менее критично.
Если вы обнаружите, что пытаетесь внедрить все больше и больше материала в оператор switch, распространяете знания о случаях вокруг или хотите, чтобы это не было так просто, просто скопируйте его, тогда пришло время реорганизовать случаи в отдельные классы.
Если у вас есть время, чтобы прочитать несколько цитат о рефакторинге операторов switch, у c2 есть очень хорошо сбалансированная страница о запахе операторов switch .
Даже в коде ООП не каждый переключатель плох. Это то, как вы используете это и почему.
источник
Автомобиль является типом государственной машины. Операторы переключения - это самый простой способ реализовать конечный автомат, в котором отсутствуют суперсостояния и субсостояния.
источник
Смена оператора не плохая. Не слушайте людей, которые говорят такие вещи, как «переключение оценок плохое»! Некоторые конкретные применения операторов switch являются антипаттернами, например использование switch для эмуляции подклассов. (Но вы также можете реализовать этот антипаттерн с помощью if, так что я думаю, что если тоже плохие!).
Ваша реализация звучит нормально. Вы правы, это будет трудно поддерживать, если вы добавите еще много состояний. Но это не просто вопрос реализации - наличие объекта со многими состояниями с различным поведением само по себе является проблемой. Во время визуализации в вашем автомобиле было 25 состояний, в каждом из которых было разное поведение и разные правила перехода между состояниями. Просто указать и задокументировать это поведение было бы огромной задачей. У вас будут тысячи правил перехода состояний! Размер
switch
будет просто симптомом более крупной проблемы. Поэтому, если возможно, избегайте идти по этому пути.Возможное решение - разбить государство на независимые подсостояния. Например, действительно ли REVERSE отличается от DRIVE? Возможно, состояние автомобиля может быть разбито на две части: состояние двигателя (ВЫКЛ, ОЖИДАНИЕ, ПРИВОД) и направление (ВПЕРЕД, ОБРАТНО). Состояние и направление движка, вероятно, будут в основном независимыми, поэтому вы уменьшите дублирование логики и правила перехода состояний. Большим количеством объектов с меньшим количеством состояний управлять намного проще, чем одному объекту с множеством состояний.
источник
В вашем примере автомобили - это просто конечные автоматы в классическом понимании информатики. У них есть небольшой, четко определенный набор состояний и какая-то логика перехода состояний.
Мое первое предложение состоит в том, чтобы рассмотреть возможность разбиения логики перехода на собственную функцию (или класс, если ваш язык не поддерживает функции первого класса).
Мое второе предложение - рассмотреть возможность разбиения логики перехода на само состояние, которое будет иметь свою собственную функцию (или класс, если ваш язык не поддерживает функции первого класса).
В любой схеме процесс перехода состояния будет выглядеть примерно так:
или же
Второе можно, конечно, тривиально обернуть в классе автомобилей, чтобы выглядеть как первое.
В обоих сценариях добавление нового состояния (скажем, DRAFTING) будет включать только добавление нового типа объекта состояния и изменение объектов, которые конкретно переключаются в новое состояние.
источник
Это зависит от того, насколько большой
switch
может быть.В вашем примере, я думаю, что все в
switch
порядке, потому что нет другого состояния, которое я мог бы придумать, которое выCar
могли бы иметь, поэтому со временем оно не увеличится.Если единственной проблемой является наличие большого переключателя, в котором у каждого
case
есть много инструкций, то просто создайте для каждого из них индивидуальные закрытые методы.Иногда люди предлагают шаблон проектирования состояния , но он более уместен, когда вы имеете дело со сложной логикой и состояниями, принимающими различные бизнес-решения для множества различных операций. В противном случае простые проблемы должны иметь простые решения.
В некоторых сценариях у вас могут быть методы, которые выполняют задачи, только когда состояние A или B, но не C или D, или есть несколько методов с очень простыми операциями, которые зависят от состояния. Тогда одно или несколько
switch
утверждений будет лучше.источник
Это звучит как машина состояния старой школы, которая использовалась до того, как кто-либо занимался объектно-ориентированным программированием, не говоря уже о шаблонах проектирования. Это может быть реализовано на любом языке, который имеет операторы switch, например C.
Как уже говорили другие, в выражениях switch нет ничего плохого. Альтернативы часто являются более сложными и трудными для понимания.
Пока количество случаев переключения не станет смехотворно большим, вещь может оставаться вполне управляемой. Первым шагом в поддержании его читабельности является замена кода в каждом случае вызовом функции для реализации поведения состояния.
источник