Извините, я не могу найти ответ на этот вопрос, я почти уверен, что кто-то уже поднимал его раньше.
Моя проблема в том, что я пишу некоторые системные библиотеки для запуска встроенных устройств. У меня есть команды, которые можно отправлять на эти устройства по радио. Это можно сделать только с помощью текста. внутри системных библиотек у меня есть поток, который обрабатывает команды, которые выглядят так
if (value.equals("A")) { doCommandA() }
else if (value.equals("B")) { doCommandB() }
else if etc.
Проблема в том, что есть много команд, которые быстро выйдут из-под контроля. Ужасно смотреть, мучительно отлаживать и ошеломляюще понять через несколько месяцев.
Ответы:
используя шаблон команды :
затем создайте
Map<String,Command>
объект и заполните егоCommand
экземплярами:тогда вы можете заменить цепочку if / else if на:
РЕДАКТИРОВАТЬ
вы также можете добавить специальные команды, такие как
UnknownCommand
илиNullCommand
, но вам понадобитсяCommandMap
команда, которая обрабатывает эти угловые случаи, чтобы минимизировать проверки клиентов.источник
Мое предложение было бы своего рода облегченной комбинацией enum и объекта Command. Это идиома, рекомендованная Джошуа Блохом в пункте 30 Эффективной Java.
Конечно, вы можете передавать параметры в doCommand или иметь возвращаемые типы.
Это решение может быть не совсем подходящим, если реализации doCommand на самом деле не «подходят» к типу перечисления, что, как обычно, когда вам приходится идти на компромисс, является немного нечетким.
источник
Имейте перечисление команд:
Если у вас больше, чем несколько команд, изучите использование шаблона Command, как указано в другом месте (хотя вы можете сохранить перечисление и встроить вызов в реализующий класс внутри перечисления вместо использования HashMap). См. Пример ответа Андреаса или Йенса на этот вопрос.
источник
Реализация интерфейса, просто и ясно продемонстрированного dfa, является чистой и элегантной (и "официально" поддерживаемым способом). Для этого и предназначена концепция интерфейса.
В C # мы могли бы использовать делегатов для программистов, которым нравится использовать указатели на функции в c, но метод DFA - это способ использовать.
У вас тоже может быть массив
Затем вы можете выполнить команду по индексу
Плагиат из DFA, но с абстрактным базовым классом вместо интерфейса. Обратите внимание на cmdKey, который будет использоваться позже. По опыту я понимаю, что часто в команде оборудования есть и подкоманды.
Постройте свои команды таким образом,
Затем вы можете расширить общий HashMap или HashTable, предоставив функцию всасывания пары ключ-значение:
Затем создайте свое хранилище команд:
Теперь вы можете отправлять контроль объективно
источник
Что ж, я предлагаю создать объекты команд и поместить их в хэш-карту, используя String as Key.
источник
Даже если я считаю, что подход с использованием командных шаблонов больше ориентирован на лучшие практики и удобен в обслуживании в долгосрочной перспективе, вот вам один вариант:
org.apache.commons.beanutils.MethodUtils.invokeMethod (это, "doCommand" + значение, ноль);
источник
Я обычно пытаюсь решить это таким образом:
у этого есть много преимуществ:
1) невозможно добавить перечисление без реализации exec. так что вы не пропустите А.
2) вам даже не нужно будет добавлять его к какой-либо карте команд, поэтому нет шаблонного кода для построения карты. просто абстрактный метод и его реализации. (который, возможно, тоже шаблонный, но короче не станет ..)
3) вы сэкономите любые потраченные впустую циклы процессора, просмотрев длинный список if или вычислив хэш-коды и выполнив поиск.
изменить: если у вас нет перечислений, но строки в качестве источника, просто используйте
Command.valueOf(mystr).exec()
для вызова метода exec. обратите внимание, что вы должны использовать модификатор public для exec, если хотите вызвать его из другого пакета.источник
Вам, вероятно, лучше всего использовать карту команд.
Но если у вас есть набор из них, чтобы справиться, вы в конечном итоге столкнетесь с множеством карт. Тогда стоит попробовать сделать это с помощью Enums.
Вы можете сделать это с помощью Enum без использования переключателей (вам, вероятно, не нужны геттеры в примере), если вы добавите метод в Enum для разрешения для «значения». Тогда вы можете просто сделать:
Обновление: добавлена статическая карта, чтобы избежать итераций при каждом вызове. Беззастенчиво ущемлен от этого ответа .
источник
На мой взгляд, ответ @dfa - лучшее решение.
Я просто предоставляю несколько фрагментов на тот случай, если вы используете Java 8 и хотите использовать Lambdas!
Команда без параметров:
(вы можете использовать Runnable вместо Command, но я не считаю это семантически правильным):
Команда с одним параметром:
Если вы ожидаете параметр, который можно использовать
java.util.function.Consumer
:В приведенном выше примере
doSomethingX
это метод, присутствующий вmyObj
классе, который принимает любой объект (названныйparam
в этом примере) в качестве аргумента.источник
если у вас есть несколько составных операторов if, то это шаблон для использования механизма правил . См., Например, JBOSS Drools .
источник
Просто используйте HashMap, как описано здесь:
источник
если бы можно было иметь массив процедур (то, что вы называете командами), которые были бы полезны ..
но вы можете написать программу для написания вашего кода. Все это очень систематично if (value = 'A') commandA (); иначе, если (........................ и т. д.
источник
Я не уверен, есть ли у вас какое-либо совпадение между поведением ваших различных команд, но вы также можете взглянуть на шаблон Chain Of Responsibility , который может обеспечить большую гибкость, позволяя нескольким командам обрабатывать некоторые входные значения.
источник
Командный шаблон - это лучший способ. Вот один пример с использованием java 8:
1. Определите интерфейс:
2. Реализуйте интерфейс с каждым расширением:
и
и так далее .....
3. Определите клиента:
4. И это пример результата:
источник
Если он много чего делает, то кода будет много, от этого никуда не деться. Просто упростите отслеживание, дайте переменным понятные имена, комментарии тоже могут помочь ...
источник