Friday, October 16, 2009

E.2. Class ATM



E.2. Class ATM


Class ATM (Figs. E.1–E.2) represents
the ATM as a whole. Figure E.1 contains the ATM
class definition, enclosed in #ifndef, #define and
#endif preprocessor directives to ensure that
this definition gets included only once in a program. We discuss lines 6–11
shortly. Lines 16–17 contain the function prototypes for the class's
public member functions. The class diagram
of Fig.
13.29 does not list any operations for class
ATM, but we now declare a public member function run
(line 17) in class ATM that allows an external client of the class
(i.e., ATMCaseStudy.cpp) to tell the ATM to run. We also include a function prototype for a
default constructor (line 16), which we discuss shortly.











Fig. E.1. Definition of class ATM, which
represents the ATM.


 

 1   // ATM.h
2 // ATM class definition. Represents an automated teller machine.
3 #ifndef ATM_H
4 #define ATM_H
5
6 #include "Screen.h" // Screen class definition
7 #include "Keypad.h" // Keypad class definition
8 #include "CashDispenser.h" // CashDispenser class definition
9 #include "DepositSlot.h" // DepositSlot class definition
10 #include "BankDatabase.h" // BankDatabase class definition
11 class Transaction; // forward declaration of class Transaction
12
13 class ATM
14 {
15 public:
16 ATM(); // constructor initializes data members
17 void run(); // start the ATM
18 private:
19 bool userAuthenticated; // whether user is authenticated
20 int currentAccountNumber; // current user's account number
21 Screen screen; // ATM's screen
22 Keypad keypad; // ATM's keypad
23 CashDispenser cashDispenser; // ATM's cash dispenser
24 DepositSlot depositSlot; // ATM's deposit slot
25 BankDatabase bankDatabase; // account information database
26
27 // private utility functions
28 void authenticateUser(); // attempts to authenticate user
29 void performTransactions(); // performs transactions
30 int displayMainMenu() const; // displays main menu
31
32 // return object of specified Transaction derived class
33 Transaction *createTransaction( int );
34 }; // end class ATM
35
36 #endif // ATM_H




Lines 19–25 of Fig. E.1 implement the class's
attributes as private data members. We
determine all but one of these attributes from the UML class diagrams of Fig.
13.28 and Fig.
13.29. Note that we implement the UML Boolean
attribute userAuthenticated in Fig.
13.29 as a bool data member in C++ (line 19).
Line 20 declares a data member not found in our UML design—an int data member currentAccountNumber that keeps track of the account number of the current
authenticated user. We'll soon see how the class uses this data member.


Lines 21–24 create objects to
represent the parts of the ATM. Recall from the class diagram of Fig.
13.28 that class ATM has
composition relationships with classes Screen, Keypad,
CashDispenser and DepositSlot, so class ATM is responsible for their creation. Line 25 creates a
BankDatabase, with which the ATM interacts to access and
manipulate bank account information. [Note: If
this were a real ATM system, the ATM class
would receive a reference to an existing database object created by the bank.
However, in this implementation we are only simulating the bank's database, so
class ATM creates the BankDatabase object with which it
interacts.] Note that lines 6–10 #include the class definitions of
Screen, Keypad, CashDispenser, DepositSlot
and BankDatabase so that the ATM can store objects of these
classes.


Lines 28–30 and 33 contain function prototypes for
private utility functions that the class uses
to perform its tasks. We'll see how these functions serve the class shortly.
Note that member function createTransaction (line 33) returns a
Transaction pointer. To include the class name
Transaction in this file, we must at least
include a forward declaration of class Transaction (line 11). Recall that a forward declaration tells the
compiler that a class exists, but that the class is defined elsewhere. A forward
declaration is sufficient here, as we are using a Transaction pointer as a return type—if we were creating or
returning an actual Transaction object, we would need to
#include the full Transaction header file.


ATM Class Member-Function Definitions


Figure
E.2 contains the member-function definitions
for class ATM. Lines 3–7 #include
the header files required by the implementation file ATM.cpp. Note that
including the ATM header file allows the
compiler to ensure that the class's member functions are defined correctly. This
also allows the member functions to use the class's data members.











Fig. E.2. ATM class member-function
definitions.


 

 1   // ATM.cpp
2 // Member-function definitions for class ATM.
3 #include "ATM.h" // ATM class definition
4 #include "Transaction.h" // Transaction class definition
5 #include "BalanceInquiry.h" // BalanceInquiry class definition
6 #include "Withdrawal.h" // Withdrawal class definition
7 #include "Deposit.h" // Deposit class definition
8
9 // enumeration constants represent main menu options
10 enum MenuOption { BALANCE_INQUIRY = 1, WITHDRAWAL, DEPOSIT, EXIT };
11
12 // ATM default constructor initializes data members
13 ATM::ATM()
14 : userAuthenticated ( false ), // user is not authenticated to start
15 currentAccountNumber( 0 ) // no current account number to start
16 {
17 // empty body
18 } // end ATM default constructor
19
20 // start ATM
21 void ATM::run()
22 {
23 // welcome and authenticate user; perform transactions
24 while ( true )
25 {
26 // loop while user is not yet authenticated
27 while ( !userAuthenticated )
28 {
29 screen.displayMessageLine( "\nWelcome!" );
30 authenticateUser(); // authenticate user
31 } // end while
32
33 performTransactions(); // user is now authenticated
34 userAuthenticated = false; // reset before next ATM session
35 currentAccountNumber = 0; // reset before next ATM session
36 screen.displayMessageLine( "\nThank you! Goodbye!" );
37 } // end while
38 } // end function run
39
40 // attempt to authenticate user against database
41 void ATM::authenticateUser()
42 {
43 screen.displayMessage( "\nPlease enter your account number: " );
44 int accountNumber = keypad.getInput(); // input account number
45 screen.displayMessage( "\nEnter your PIN: " ); // prompt for PIN
46 int pin = keypad.getInput(); // input PIN
47
48 // set userAuthenticated to bool value returned by database
49 userAuthenticated =
50 bankDatabase.authenticateUser( accountNumber, pin );
51
52 // check whether authentication succeeded
53 if ( userAuthenticated )
54 {
55 currentAccountNumber = accountNumber; // save user's account #
56 } // end if
57 else
58 screen.displayMessageLine(
59 "Invalid account number or PIN. Please try again." );
60 } // end function authenticateUser
61
62 // display the main menu and perform transactions
63 void ATM::performTransactions()
64 {
65 // local pointer to store transaction currently being processed
66 Transaction *currentTransactionPtr;
67
68 bool userExited = false; // user has not chosen to exit
69
70 // loop while user has not chosen option to exit system
71 while ( !userExited )
72 {
73 // show main menu and get user selection
74 int mainMenuSelection = displayMainMenu();
75
76 // decide how to proceed based on user's menu selection
77 switch ( mainMenuSelection )
78 {
79 // user chose to perform one of three transaction types
80 case BALANCE_INQUIRY:
81 case WITHDRAWAL:
82 case DEPOSIT:
83 // initialize as new object of chosen type
84 currentTransactionPtr =
85 createTransaction( mainMenuSelection );
86
87 currentTransactionPtr->execute(); // execute transaction
88
89 // free the space for the dynamically allocated Transaction
90 delete currentTransactionPtr;
91
92 break;
93 case EXIT: // user chose to terminate session
94 screen.displayMessageLine( "\nExiting the system..." );
95 userExited = true; // this ATM session should end
96 break;
97 default: // user did not enter an integer from 1-4
98 screen.displayMessageLine(
99 "\nYou did not enter a valid selection. Try again." );
100 break;
101 } // end switch
102 } // end while
103 } // end function performTransactions
104
105 // display the main menu and return an input selection
106 int ATM::displayMainMenu() const
107 {
108 screen.displayMessageLine( "\nMain menu:" );
109 screen.displayMessageLine( "1 - View my balance" );
110 screen.displayMessageLine( "2 - Withdraw cash" );
111 screen.displayMessageLine( "3 - Deposit funds" );
112 screen.displayMessageLine( "4 - Exit\n" );
113 screen.displayMessage( "Enter a choice: " );
114 return keypad.getInput(); // return user's selection
115 } // end function displayMainMenu
116
117 // return object of specified Transaction derived class
118 Transaction *ATM::createTransaction( int type )
119 {
120 Transaction *tempPtr; // temporary Transaction pointer
121
122 // determine which type of Transaction to create
123 switch ( type )
124 {
125 case BALANCE_INQUIRY: // create new BalanceInquiry transaction
126 tempPtr = new BalanceInquiry(
127 currentAccountNumber, screen, bankDatabase );
128 break;
129 case WITHDRAWAL: // create new Withdrawal transaction
130 tempPtr = new Withdrawal( currentAccountNumber, screen,
131 bankDatabase, keypad, cashDispenser );
132 break;
133 case DEPOSIT: // create new Deposit transaction
134 tempPtr = new Deposit( currentAccountNumber, screen,
135 bankDatabase, keypad, depositSlot );
136 break;
137 } // end switch
138
139 return tempPtr; // return the newly created object
140 } // end function createTransaction




Line 10 declares an enum named MenuOption that contains constants corresponding to the four options
in the ATM's main menu (i.e., balance inquiry, withdrawal, deposit and exit).
Note that setting BALANCE_INQUIRY to 1 causes the subsequent enumeration constants to be
assigned the values 2, 3 and 4, as enumeration
constant values increment by 1.


Lines 13–18 define class ATM's constructor, which
initializes the class's data members. When an ATM object is first created, no user is
authenticated, so line 14 uses a member initializer to set
userAuthenticated to false. Likewise, line 15
initializes currentAccountNumber to 0
because there is no current user yet.


ATM member function run
(lines 21–38) uses an infinite loop (lines 24–37) to repeatedly welcome a user,
attempt to authenticate the user and, if authentication succeeds, allow the user
to perform transactions. After an authenticated user performs the desired
transactions and chooses to exit, the ATM resets itself, displays a goodbye
message to the user and restarts the process. We use an infinite loop here to
simulate the fact that an ATM appears to run continuously until the bank turns
it off (an action beyond the user's control). An ATM user has the option to exit
the system, but does not have the ability to turn off the ATM completely.


Inside member function run's infinite loop, lines 27–31 cause the ATM to repeatedly
welcome and attempt to authenticate the user as long as the user has not been
authenticated (i.e., !userAuthenticated is true). Line 29
invokes member function displayMessageLine of the ATM's
screen to display a welcome message. Like Screen member
function displayMessage designed in the case study, member function
displayMessageLine (declared in line 13 of Fig. E.3 and defined in lines 20–23
of Fig. E.4) displays a message to the user, but this member function
also outputs a newline after displaying the message. We have added this member
function during implementation to give class Screen's clients more control over the placement of
displayed messages. Line 30 of Fig. E.2 invokes class
ATM's private utility function authenticateUser (lines 41–60) to attempt to authenticate the user.











Fig. E.3. Screen class
definition.


 

 1   // Screen.h
2 // Screen class definition. Represents the screen of the ATM.
3 #ifndef SCREEN_H
4 #define SCREEN_H
5
6 #include <string>
7 using std::string;
8
9 class Screen
10 {
11 public:
12 void displayMessage( string ) const; // output a message
13 void displayMessageLine( string ) const; // output message with newline
14 void displayDollarAmount( double ) const; // output a dollar amount
15 }; // end class Screen
16
17 #endif // SCREEN_H













Fig. E.4. Screen class member-function
definitions.


 

 1   // Screen.cpp
2 // Member-function definitions for class Screen.
3 #include <iostream>
4 using std::cout;
5 using std::endl;
6 using std::fixed;
7
8 #include <iomanip>
9 using std::setprecision;
10
11 #include "Screen.h" // Screen class definition
12
13 // output a message without a newline
14 void Screen::displayMessage( string message ) const
15 {
16 cout << message;
17 } // end function displayMessage
18
19 // output a message with a newline
20 void Screen::displayMessageLine( string message ) const
21 {
22 cout << message << endl;
23 } // end function displayMessageLine
24
25 // output a dollar amount
26 void Screen::displayDollarAmount( double amount ) const
27 {
28 cout << fixed << setprecision( 2 ) << "$" << amount;
29 } // end function displayDollarAmount




We refer to the requirements
specification to determine the steps necessary to authenticate the user before
allowing transactions to occur. Line 43 of member function
authenticateUser invokes member function
displayMessage of the ATM's screen to prompt the user to enter an account number. Line 44
invokes member function getInput of the ATM's
keypad to obtain the user's input, then
stores the integer value entered by the user in a local variable
accountNumber. Member function authenticateUser next prompts the user to enter a PIN (line 45), and stores
the PIN input by the user in a local variable pin (line 46). Next, lines 49–50 attempt to
authenticate the user by passing the accountNumber and pin
entered by the user to the bankDatabase's authenticateUser
member function. Class ATM sets its userAuthenticated data
member to the bool value returned by this
function—userAuthenticated becomes true if authentication
succeeds (i.e., accountNumber and pin match those of an
existing Account in bankDatabase) and remains false
otherwise. If userAuthenticated is true, line 55 saves the
account number entered by the user (i.e., accountNumber) in the
ATM data member currentAccountNumber. The other member
functions of class ATM use this variable
whenever an ATM session requires access to the user's account number. If
userAuthenticated is false, lines 58–59 use the
screen's displayMessageLine
member function to indicate that an invalid account number and/or PIN was
entered and the user must try again. Note that we set
currentAccountNumber only after
authenticating the user's account number and the associated PIN—if the database
could not authenticate the user, currentAccountNumber remains
0.


After member function run attempts to authenticate the
user (line 30), if userAuthenticated is still false, the
while loop in lines 27–31 executes again. If userAuthenticated
is now true, the loop terminates and control
continues with line 33, which calls class ATM's utility function
performTransactions.


Member function performTransactions (lines 63–103) carries out an ATM session for an
authenticated user. Line 66 declares a local Transaction pointer, which we aim at a BalanceInquiry,
Withdrawal or Deposit object
representing the ATM transaction currently being processed. Note that we use a
Transaction pointer here to allow us to take
advantage of polymorphism. Also note that we use the role name included in the
class diagram of Fig.
3.20—currentTransaction—in naming this pointer. As per our
pointernaming convention, we append "Ptr" to the role name to form the
variable name currentTransactionPtr. Line 68 declares another local
variable—a bool called userExited
that keeps track of whether the user has chosen to exit. This variable controls
a while loop (lines 71–102) that allows the
user to execute an unlimited number of transactions before choosing to exit.
Within this loop, line 74 displays the main menu and obtains the user's menu
selection by calling an ATM utility function displayMainMenu (defined in lines 106–115). This member function
displays the main menu by invoking member functions of the ATM's
screen and returns a menu selection obtained from the
user through the ATM's keypad. Note
that this member function is const because it
does not modify the contents of the object. Line 74 stores the user's selection
returned by displayMainMenu in local variable
mainMenuSelection.


After obtaining a main menu selection,
member function performTransactions uses a switch statement (lines 77–101) to respond to the selection
appropriately. If mainMenuSelection is equal to
any of the three enumeration constants representing transaction types (i.e., if
the user chose to perform a transaction), lines 84–85 call utility function
createTransaction (defined in lines 118–140) to
return a pointer to a newly instantiated object of the type that corresponds to
the selected transaction. Pointer currentTransactionPtr is assigned the
pointer returned by createTransaction. Line 87 then uses
currentTransactionPtr to invoke the new object's execute
member function to execute the transaction. We'll discuss Transaction
member function execute and the three Transaction derived
classes shortly. Finally, when the Transaction derived class object is no longer needed, line 90
releases the memory dynamically allocated for it.


Note that we aim the Transaction
pointer currentTransactionPtr at an object of one of the three
Transaction derived classes so that we can
execute transactions polymorphically. For example, if the user chooses to
perform a balance inquiry, mainMenuSelection equals
BALANCE_INQUIRY, leading createTransaction to return a pointer to a BalanceInquiry object.
Thus, currentTransactionPtr points to a BalanceInquiry, and
invoking currentTransactionPtr->execute() results in
BalanceInquiry's version of execute being called.


Member function createTransaction (lines 118–140) uses
a switch statement (lines 123–137) to instantiate a
new Transaction derived class object of the
type indicated by the parameter type. Recall that
member function performTransactions passes mainMenuSelection
to this member function only when mainMenuSelection contains a value corresponding to one of the three
transaction types. Therefore type equals either
BALANCE_INQUIRY, WITHDRAWAL or DEPOSIT. Each
case in the switch statement aims the temporary pointer
tempPtr at a newly created object of the
appropriate Transaction derived class.
Note that each constructor has a unique parameter list, based on the specific
data required to initialize the derived class object. A
BalanceInquiry requires only the account
number of the current user and references to the ATM's
screen and the bankDatabase. In addition to these parameters, a
Withdrawal requires references to the ATM's
keypad and cashDispenser, and a Deposit requires references to the ATM's keypad and
depositSlot. Note that, as you'll soon see, the
BalanceInquiry, Withdrawal and Deposit constructors each specify reference parameters to
receive the objects representing the required parts of the ATM. Thus, when
member function createTransaction passes objects in the ATM
(e.g., screen and keypad) to the initializer for each newly
created Transaction derived class object, the new object actually
receives references to the ATM's composite objects. We discuss the transaction classes
in more detail in Sections
E.9–E.12.


After executing a transaction (line 87 in
performTransactions), userExited remains false and
the while loop in lines 71–102 repeats, returning
the user to the main menu. However, if a user does not perform a transaction and
instead selects the main menu option to exit, line 95 sets userExited to true, causing the condition of the
while loop (!userExited) to become false. This
while is the final statement of member
function performTransactions, so control
returns to the calling function run. If the
user enters an invalid main menu selection (i.e., not an integer from 1–4),
lines 98–99 display an appropriate error message, userExited remains
false and the user returns to the main menu to try again.


When performTransactions returns control to member
function run, the user has chosen to exit the system,
so lines 34–35 reset the ATM's data members userAuthenticated
and currentAccountNumber to prepare for the
next ATM user. Line 36 displays a goodbye message before the ATM starts over and
welcomes the next user.


 


No comments:

Post a Comment