Поскольку мы не возбуждаем исключения, если сообщение обработало, то теперь в цикле (1) нужно проверять, обработали мы сообщение или нет. Обработка прекращается, как только сообщение успешно обработало, чтобы в следующий раз можно было ждать очередного набора сообщений. Если найдено соответствие указанному типу сообщения, то вызывается предоставленная функция (2), а не возбуждается исключение (хотя функция-обработчик может и сама возбудить исключение). Если же соответствие не найдено, то мы передаем сообщение предыдущему диспетчеру в цепочке (3). В самом первом экземпляре это будет объект dispatcher
, но если в функции handle()
(4) вызовы сцеплялись, чтобы можно было обработать несколько типов сообщений, то предыдущим диспетчером может быть ранее созданный экземпляр TemplateDispatcher<>
, который в свою очередь передаст сообщение предшествующему ему диспетчеру в цепочке, если не сможет обработать его сам. Поскольку любой обработчик может возбудить исключение (в том числе и обработчик самого первого объекта dispatcher
, если встретит сообщение close_queue
), то деструктор снова необходимо снабдить аннотацией noexcept(false)
(5).
Этот простенький каркас позволяет помещать в очередь сообщения любого типа, а затем на принимающем конце отбирать те из них, которые мы можем обработать. Кроме того, он позволяет передавать ссылку на очередь, чтобы в нее можно было добавлять новые сообщения, оставляя при этом прижимающий конец недоступным извне.
И чтобы закончить пример из главы 4, в листинге С.6 приведён код сообщений, в листингах С.7, С.8 и С.9 — различные конечные автоматы, а в листинге С.10 — управляющая программа.
Листинг С.6. Сообщения банкомата
struct withdraw {
std::string account;
unsigned amount;
mutable messaging::sender atm_queue;
withdraw(std::string const& account_,
unsigned amount_, messaging::sender atm_queue_):
account(account_), amount(amount_), atm_queue(atm_queue_) {}
};
struct withdraw_ok {};
struct withdraw_denied {};
struct cancel_withdrawal {
std::string account;
unsigned amount;
cancel_withdrawal(std::string const& account_,
unsigned amount_):
account(account_), amount(amount_) {}
};
struct withdrawal_processed {
std::string account;
unsigned amount;
withdrawal_processed(std::string const& account_,
unsigned amount_):
account(account_), amount(amount_) {}
};
struct card_inserted {
std::string account;
explicit card_inserted(std::string const& account_):
account(account_) {}
};
struct digit_pressed {
char digit;
explicit digit_pressed(char digit_):
digit(digit_) {}
};
struct clear_last_pressed {};
struct eject_card {};
struct withdraw_pressed {
unsigned amount;
explicit withdraw_pressed(unsigned amount_):
amount(amount_) {}
};
struct cancel_pressed {};
struct issue_money {
unsigned amount;
issue_money(unsigned amount_):
amount(amount_) {}
};
struct verify_pin {
std::string account;
std::string pin;
mutable messaging::sender atm_queue;
verify_pin(std::string const& account_, std::string const& pin_,
messaging::sender atm_queue_):
account(account_), pin(pin_), atm_queue(atm_queue_) {}
};
struct pin_verified {};
struct pin_incorrect {};
struct display_enter_pin {};
struct display_enter_card {};
struct display_insufficient_funds {};
struct display_withdrawal_cancelled {};
struct display_pin_incorrect_message {};
struct display_withdrawal_options (};
struct get_balance {