Параллельное программирование на С++ в действии — страница 43 из 53

 mutable messaging::sender atm_queue;


 get_balance(

  std::string const& account_, messaging::sender atm_queue_):

   account(account_), atm_queue(atm_queue_) {}

};


struct balance {

 unsigned amount;


 explicit balance(unsigned amount_):

  amount(amount_) {}

};


struct display_balance {

 unsigned amount;


 explicit display_balance(unsigned amount_):

  amount(amount_) {}

};


struct balance_pressed {};


Листинг С.7. Конечный автомат банкомата

class atm {

 messaging::receiver incoming;

 messaging::sender bank;

 messaging::sender interface_hardware;

 void (atm::*state)();

 std::string account;

 unsigned withdrawal_amount;

 std::string pin;


 void process_withdrawal() {

  incoming.wait().handle(

   [&](withdraw_ok const& msg) {

    interface_hardware.send(

     issue_money(withdrawal_amount));

    bank.send(

     withdrawal_processed(account, withdrawal_amount));

    state = &atm::done_processing;

   }

  ).handle(

   [&](withdraw_denied const& msg) {

    interface_hardware.send(display_insufficient_funds());

    state = &atm::done_processing;

   }

  ).handle(

   [&](cancel_pressed const& msg) {

    bank.send(

     cancel_withdrawal(account, withdrawal_amount));

    interface_hardware.send(

     display_withdrawal_cancelled());

    state = &atm::done_processing;

   }

  );

 }


 void process_balance() {

  incoming.wait().handle(

   [&](balance const& msg) {

    interface_hardware.send(display_balance(msg.amount));

    state = &atm::wait_for_action;

   }

  ).handle(

   [&](cancel_pressed const& msg) {

    state = &atm::done_processing;

   }

  );

 }


 void wait_for_action() {

  interface_hardware.send(display_withdrawal_options());

  incoming.wait().handle(

   [&](withdraw_pressed const& msg) {

    withdrawal_amount = msg.amount;

    bank.send(withdraw(account, msg.amount, incoming));

    state = &atm::process_withdrawal;

   }

  ).handle(

   [&](balance_pressed const& msg) {

    bank.send(get_balance(account, incoming));

    state = &atm::process_balance;

   }

  ).handle(

   [&](cancel_pressed const& msg) {

    state = &atm::done_processing;

   }

  );

 }


 void verifying_pin() {

  incoming.wait().handle(

   [&](pin_verified const& msg) {

    state = &atm::wait_for_action;

   }

  ).handle(

   [&](pin_incorrect const& msg) {

    interface_hardware.send(

     display_pin_incorrect_message());

    state = &atm::done_processing;

   }

  ).handle(

   [&](cancel_pressed const& msg) {

    state = &atm::done_processing;

   }

  );

 }


 void getting_pin() {

  incoming.wait().handle(

   [&](digit_pressed const& msg) {

    unsigned const pin_length = 4;

    pin += msg.digit;

    if (pin.length() == pin_length) {

     bank.send(verify_pin(account, pin, incoming));

     state = &atm::verifying_pin;

    }

   }

  ).handle(

   [&](clear_last_pressed const& msg) {

    if (!pin.empty()) {

     pin.pop_back();

    }

   }

  ).handle(

   [&](cancel_pressed const& msg) {

    state = &atm::done_processing;

   }

  );

 }


 void waiting_for_card() {

  interface_hardware.send(display_enter_card());

  incoming.wait().handle(

   [&](card_inserted const& msg) {

    account = msg.account;

    pin = "";

    interface_hardware.send(display_enter_pin());

    state = &atm::getting_pin;

   }

  );

 }


 void done_processing() {

  interface_hardware.send(eject_card());

  state = &atm::waiting_for_card;

 }


 atm(atm const&) = delete;

 atm& operator=(atm const&) = delete;


public:

 atm(messaging::sender bank_,

  messaging::sender interface_hardware_):

   bank(bank_), interface_hardware(interface_hardware_) {}


 void done() {

  get_sender().send(messaging::close_queue());

 }


 void run() {

  state = &atm::waiting_for_card;

  try {

   for (;;) {

    (this->*state)();

   }

  } catch(messaging::close_queue const&) {

  }

 }


 messaging::sender get_sender() {

  return incoming;

 }