Я внедряю бот IRC, который получает сообщение, и я проверяю это сообщение, чтобы определить, какие функции вызывать. Есть ли более умный способ сделать это? Кажется, что это быстро выйдет из-под контроля после того, как я наберу 20 команд.
Возможно, есть лучший способ абстрагировать это?
public void onMessage(String channel, String sender, String login, String hostname, String message){
if (message.equalsIgnoreCase(".np")){
// TODO: Use Last.fm API to find the now playing
} else if (message.toLowerCase().startsWith(".register")) {
cmd.registerLastNick(channel, sender, message);
} else if (message.toLowerCase().startsWith("give us a countdown")) {
cmd.countdown(channel, message);
} else if (message.toLowerCase().startsWith("remember am routine")) {
cmd.updateAmRoutine(channel, message, sender);
}
}
java
design
abstraction
Харрисон Нгуен
источник
источник
Ответы:
Используйте таблицу отправки . Это таблица, содержащая пары («часть сообщения»,
pointer-to-function
). Тогда диспетчер будет выглядеть так (в псевдокоде):(
equalsIgnoreCase
может быть обработан как особый случай где-то ранее, или, если у вас много таких тестов, со второй таблицей отправки).Конечно, то, что
pointer-to-function
должно выглядеть, зависит от вашего языка программирования. Вот пример на C или C ++. В Java или C # вы, вероятно, будете использовать лямбда-выражения для этой цели, или вы будете имитировать «указатель на функции», используя шаблон команды. В бесплатной онлайн-книге « Perl высшего порядка » есть полная глава о таблицах отправки с использованием Perl.источник
equalsIgnoreCase
для «сейчас играет», ноtoLowerCase().startsWith
для других.toLowerCase
операцию из цикла.Я бы, наверное, сделал что-то вроде этого:
Затем вы можете заставить каждую команду реализовать этот интерфейс и возвращать true, когда оно соответствует сообщению.
источник
Command
оно более автономно, если оно знает, когда вызывать себя. Это приводит к небольшим издержкам, если список команд огромен, но это, вероятно, незначительно.equals
иhashCode
будет таким же, как строка, представляющая командуВы используете Java - так что сделайте это красиво ;-)
Я бы, вероятно, сделал это с помощью аннотаций:
Создайте пользовательскую аннотацию метода
Добавьте аннотацию ко всем соответствующим методам в классе, например
В вашем конструкторе используйте Reflections для создания HashMap методов из всех аннотированных методов в вашем классе:
В вашем
onMessage
методе просто сделайте цикл,commandList
пытаясь сопоставить строку с каждым и вызываяmethod.invoke()
там, где он подходит.источник
Что если вы определите интерфейс, скажем, у
IChatBehaviour
которого есть один вызванный метод,Execute
который принимает объектmessage
иcmd
объект:Затем в своем коде вы реализуете этот интерфейс и определяете желаемое поведение:
И так далее для всего остального.
В вашем основном классе у вас есть список поведений (
List<IChatBehaviour>
), которые реализует ваш IRC-бот. Затем вы можете заменить своиif
заявления чем-то вроде этого:Выше должно уменьшить количество кода, который у вас есть. Вышеуказанный подход также позволит вам предоставить дополнительные варианты поведения вашему классу ботов без изменения самого класса ботов (согласно
Strategy Design Pattern
).Если вы хотите, чтобы одновременно запускалось только одно поведение, вы можете изменить сигнатуру
execute
метода на yieldtrue
(false
поведение сработало ) или (поведение не сработало) и заменить приведенный выше цикл следующим образом:Вышеприведенное было бы более утомительным для реализации и инициализации, поскольку вам нужно создавать и передавать все дополнительные классы, однако это должно сделать вашего бота легко расширяемым и модифицируемым, поскольку все ваши классы поведения будут инкапсулированы и, будем надеяться, независимы друг от друга.
источник
if
? Т.е. как вы решаете, что поведение выполняется для команды?if
роль в поведении).IChatBehaviour
может ли данное лицо обрабатывать данную команду, поскольку она позволяет вызывающей стороне делать больше с ней, например, обрабатывать ошибки, если ни одна из команд не соответствует, хотя на самом деле это всего лишь личное предпочтение. Если это не нужно, то нет смысла бесполезно усложнять код.«Интеллигентным» может быть (как минимум) три вещи:
Более высокая производительность
Таблица рассылки (и ее эквиваленты) является хорошим предложением. Такая таблица называлась "CADET" в прошлые годы для "Не могу добавить; даже не пытается". Однако, рассмотрите комментарий, чтобы помочь начинающему сопровождающему только о том, как управлять упомянутой таблицей.
Ремонтопригодность
«Сделай это красиво» - не пустое наставление.
и часто упускают из виду ...
упругость
Использование toLowerCase имеет недостатки в том, что некоторые тексты на некоторых языках должны претерпевать болезненную реструктуризацию при переключении между волшебным и незначительным. К сожалению, такие же подводные камни существуют для toUpperCase. Просто будь в курсе.
источник
Вы можете сделать так, чтобы все команды реализовывали один и тот же интерфейс. Тогда парсер сообщений может вернуть вам соответствующую команду, которую вы только выполните.
Похоже, просто больше кода. Да, вам все еще нужно проанализировать сообщение, чтобы узнать, какую команду выполнить, но теперь оно находится в правильно определенной точке. Это может быть использовано в другом месте. (Возможно, вы захотите внедрить MessageParser, но это другой вопрос. Кроме того, шаблон Flyweight может быть хорошей идеей для команд, в зависимости от того, сколько вы ожидаете создать.)
источник
Что бы я сделал, это:
Это сделает это более управляемым. Больше пользы, когда число «еще, если» растет слишком сильно.
Конечно, иногда иметь это «если бы еще» не было большой проблемой. Я не думаю, что 20 это так плохо.
источник