Я тоже боролся с этой проблемой. Мой подход заключается в использовании дерева, где каждое состояние ussd является узлом. Позволь мне осветить меня как можно лучше
interface Node {
render(),
process(input)
}
Узлы подразделяются на узлы выбора и ввода.
Выбор
Узлы выбора просто предоставляют пользователям опции, из которых можно выбрать, затем отсылают пользователя к одному из его дочерних узлов или отображают сообщение об ошибке
class Selection extends Node {
Node[] children;
string title;
render() {
// create a ussd menu here appending title to
// menu items based on this.children
}
process(input) {
// get input and select from children node
// call its render method
}
}
Input
Узлы ввода собирают фактические данные от пользователей (например, имена, номер ваучера и т. Д.) И выполняют обработку, например, выполняют запрос к базе данных или вызывают удаленный API, а затем представляют пользователю ответ.
class Input extends Node {
string title;
string instruction;
Handler handler;
render() {
// show title and/or instruction to user
}
process(input) {
// validate input and then pass to this.handler
}
}
Чтобы дополнительно отделить логику, я добавил интерфейс обработчика, каждый узел ввода должен иметь обработчик. Вся логика обработки находится в обработчике
interface Handler {
handle()
}
Резольвер
Теперь с помощью этого вы создаете класс Resolver, который обрабатывает информацию о сеансе ussd и все http-содержимое (если вы получаете запросы ussd через http). Resolver также пересекает дерево на основе пользовательского ввода, чтобы собрать ответственный узел, а затем либо вызывает его метод визуализации, либо обрабатывает метод. Ваше дерево выглядит примерно так
new Selection('Main Menu (title)', [
new Selection('My account', [...]),
new Input('Recharge', 'Enter voucher number', new RechargeHandler())
]);
Это ограниченное решение, характерное для моего варианта использования, и я считаю, что оно может быть расширено для других ситуаций. Я хотел бы услышать, как все остальные решают эту проблему