6.22. (Optional) Software Engineering Case Study: Identifying Class Operations in the ATM System
In the "Software Engineering Case Study" sections at the ends of Chapters 3, 4 and 5, we performed the first few steps in the object-oriented design of our ATM system. In Chapter 3, we identified the classes that we will need to implement and we created our first class diagram. In Chapter 4, we described some attributes of our classes. In Chapter 5, we examined objects' states and modeled objects' state transitions and activities. In this section, we determine some of the class operations (or behaviors) needed to implement the ATM system.
An operation is a service that objects of a class provide to clients of the class. Consider the operations of some real-world objects. A radio's operations include setting its station and volume (typically invoked by a person adjusting the radio's controls). A car's operations include accelerating (invoked by the driver pressing the accelerator pedal), decelerating (invoked by the driver pressing the brake pedal or releasing the gas pedal), turning and shifting gears. Software objects can offer operations as wellfor example, a software graphics object might offer operations for drawing a circle, drawing a line, drawing a square and the like. A spreadsheet software object might offer operations like printing the spreadsheet, totaling the elements in a row or column and graphing information in the spreadsheet as a bar chart or pie chart.
We can derive many of the operations of each class by examining the key verbs and verb phrases in the requirements document. We then relate each of these to particular classes in our system (Fig. 6.34). The verb phrases in Fig. 6.34 help us determine the operations of each class.
Figure 6.34. Verbs and verb phrases for each class in the ATM system.
Verbs and verb phrases
executes financial transactions
[none in the requirements document]
[none in the requirements document]
[none in the requirements document]
authenticates a user, retrieves an account balance, credits a deposit amount to an account, debits a withdrawal amount from an account
retrieves an account balance, credits a deposit amount to an account, debits a withdrawal amount from an account
displays a message to the user
receives numeric input from the user
dispenses cash, indicates whether it contains enough cash to satisfy a withdrawal request
receives a deposit envelope
To identify operations, we examine the verb phrases listed for each class in Fig. 6.34. The "executes financial transactions" phrase associated with class ATM implies that class ATM instructs transactions to execute. Therefore, classes BalanceInquiry, Withdrawal and Deposit each need an operation to provide this service to the ATM. We place this operation (which we have named execute) in the third compartment of the three transaction classes in the updated class diagram of Fig. 6.35. During an ATM session, the ATM object will invoke the execute operation of each transaction object to tell it to execute.
Figure 6.35. Classes in the ATM system with attributes and operations.
(This item is displayed on page 300 in the print version)
The UML represents operations (which are implemented as member functions in C++) by listing the operation name, followed by a comma-separated list of parameters in parentheses, a colon and the return type:
operationName ( parameter1, parameter2, ..., parameterN ) : return type
Each parameter in the comma-separated parameter list consists of a parameter name, followed by a colon and the parameter type:
parameterName : parameterType
For the moment, we do not list the parameters of our operationswe will identify and model the parameters of some of the operations shortly. For some of the operations, we do not yet know the return types, so we also omit them from the diagram. These omissions are perfectly normal at this point. As our design and implementation proceed, we will add the remaining return types.
Operations of Class BankDatabase and Class Account
Figure 6.34 lists the phrase "authenticates a user" next to class BankDatabasethe database is the object that contains the account information necessary to determine whether the account number and PIN entered by a user match those of an account held at the bank. Therefore, class BankDatabase needs an operation that provides an authentication service to the ATM. We place the operation authenticateUser in the third compartment of class BankDatabase (Fig. 6.35). However, an object of class Account, not class BankDatabase, stores the account number and PIN that must be accessed to authenticate a user, so class Account must provide a service to validate a PIN obtained through user input against a PIN stored in an Account object. Therefore, we add a validatePIN operation to class Account. Note that we specify a return type of Boolean for the authenticateUser and validatePIN operations. Each operation returns a value indicating either that the operation was successful in performing its task (i.e., a return value of true) or that it was not (i.e., a return value of false).
Figure 6.34 lists several additional verb phrases for class BankDatabase: "retrieves an account balance," "credits a deposit amount to an account" and "debits a withdrawal amount from an account." Like "authenticates a user," these remaining phrases refer to services that the database must provide to the ATM, because the database holds all the account data used to authenticate a user and perform ATM transactions. However, objects of class Account actually perform the operations to which these phrases refer. Thus, we assign an operation to both class BankDatabase and class Account to correspond to each of these phrases. Recall from Section 3.11 that, because a bank account contains sensitive information, we do not allow the ATM to access accounts directly. The database acts as an intermediary between the ATM and the account data, thus preventing unauthorized access. As we will see in Section 7.12, class ATM invokes the operations of class BankDatabase, each of which in turn invokes the operation with the same name in class Account.
The phrase "retrieves an account balance" suggests that classes BankDatabase and Account each need a getBalance operation. However, recall that we created two attributes in class Account to represent a balanceavailableBalance and totalBalance. A balance inquiry requires access to both balance attributes so that it can display them to the user, but a withdrawal needs to check only the value of availableBalance. To allow objects in the system to obtain each balance attribute individually, we add operations getAvailableBalance and getTotalBalance to the third compartment of classes BankDatabase and Account (Fig. 6.35). We specify a return type of Double for each of these operations, because the balance attributes which they retrieve are of type Double.
The phrases "credits a deposit amount to an account" and "debits a withdrawal amount from an account" indicate that classes BankDatabase and Account must perform operations to update an account during a deposit and withdrawal, respectively. We therefore assign credit and debit operations to classes BankDatabase and Account. You may recall that crediting an account (as in a deposit) adds an amount only to the totalBalance attribute. Debiting an account (as in a withdrawal), on the other hand, subtracts the amount from both balance attributes. We hide these implementation details inside class Account. This is a good example of encapsulation and information hiding.
If this were a real ATM system, classes BankDatabase and Account would also provide a set of operations to allow another banking system to update a user's account balance after either confirming or rejecting all or part of a deposit. Operation confirmDepositAmount, for example, would add an amount to the availableBalance attribute, thus making deposited funds available for withdrawal. Operation rejectDepositAmount would subtract an amount from the totalBalance attribute to indicate that a specified amount, which had recently been deposited through the ATM and added to the totalBalance, was not found in the deposit envelope. The bank would invoke this operation after determining either that the user failed to include the correct amount of cash or that any checks did not clear (i.e, they "bounced"). While adding these operations would make our system more complete, we do not include them in our class diagrams or our implementation because they are beyond the scope of the case study.
Operations of Class Screen
Class Screen "displays a message to the user" at various times in an ATM session. All visual output occurs through the screen of the ATM. The requirements document describes many types of messages (e.g., a welcome message, an error message, a thank-you message) that the screen displays to the user. The requirements document also indicates that the screen displays prompts and menus to the user. However, a prompt is really just a message describing what the user should input next, and a menu is essentially a type of prompt consisting of a series of messages (i.e., menu options) displayed consecutively. Therefore, rather than assign class Screen an individual operation to display each type of message, prompt and menu, we simply create one operation that can display any message specified by a parameter. We place this operation (displayMessage) in the third compartment of class Screen in our class diagram (Fig. 6.35). Note that we do not worry about the parameter of this operation at this timewe model the parameter later in this section.
Operations of Class Keypad
From the phrase "receives numeric input from the user" listed by class Keypad in Fig. 6.34, we conclude that class Keypad should perform a getInput operation. Because the ATM's keypad, unlike a computer keyboard, contains only the numbers 09, we specify that this operation returns an integer value. Recall from the requirements document that in different situations the user may be required to enter a different type of number (e.g., an account number, a PIN, the number of a menu option, a deposit amount as a number of cents). Class Keypad simply obtains a numeric value for a client of the classit does not determine whether the value meets any specific criteria. Any class that uses this operation must verify that the user enters appropriate numbers, and if not, display error messages via class Screen). [Note: When we implement the system, we simulate the ATM's keypad with a computer keyboard, and for simplicity we assume that the user does not enter nonnumeric input using keys on the computer keyboard that do not appear on the ATM's keypad. Later in the book, you will learn how to examine inputs to determine if they are of particular types.]
Operations of Class CashDispenser and Class DepositSlot
Figure 6.34 lists "dispenses cash" for class CashDispenser. Therefore, we create operation dispenseCash and list it under class CashDispenser in Fig. 6.35. Class CashDispenser also "indicates whether it contains enough cash to satisfy a withdrawal request." Thus, we include isSufficientCashAvailable, an operation that returns a value of UML type Boolean, in class CashDispenser. Figure 6.34 also lists "receives a deposit envelope" for class DepositSlot. The deposit slot must indicate whether it received an envelope, so we place an operation isEnvelopeReceived, which returns a Boolean value, in the third compartment of class DepositSlot. [Note: A real hardware deposit slot would most likely send the ATM a signal to indicate that an envelope was received. We simulate this behavior, however, with an operation in class DepositSlot that class ATM can invoke to find out whether the deposit slot received an envelope.]
Operations of Class ATM
We do not list any operations for class ATM at this time. We are not yet aware of any services that class ATM provides to other classes in the system. When we implement the system with C++ code, however, operations of this class, and additional operations of the other classes in the system, may emerge.
Identifying and Modeling Operation Parameters
So far, we have not been concerned with the parameters of our operationswe have attempted to gain only a basic understanding of the operations of each class. Let's now take a closer look at some operation parameters. We identify an operation's parameters by examining what data the operation requires to perform its assigned task.
Consider the authenticateUser operation of class BankDatabase. To authenticate a user, this operation must know the account number and PIN supplied by the user. Thus we specify that operation authenticateUser takes integer parameters userAccountNumber and userPIN, which the operation must compare to the account number and PIN of an Account object in the database. We prefix these parameter names with "user" to avoid confusion between the operation's parameter names and the attribute names that belong to class Account. We list these parameters in the class diagram in Fig. 6.36 that models only class BankDatabase. [Note: It is perfectly normal to model only one class in a class diagram. In this case, we are most concerned with examining the parameters of this one class in particular, so we omit the other classes. In class diagrams later in the case study, in which parameters are no longer the focus of our attention, we omit these parameters to save space. Remember, however, that the operations listed in these diagrams still have parameters.]
Figure 6.36. Class BankDatabase with operation parameters.
Recall that the UML models each parameter in an operation's comma-separated parameter list by listing the parameter name, followed by a colon and the parameter type (in UML notation). Figure 6.36 thus specifies that operation authenticateUser takes two parametersuserAccountNumber and userPIN, both of type Integer. When we implement the system in C++, we will represent these parameters with int values.
Class BankDatabase operations getAvailableBalance, getTotalBalance, credit and debit also each require a userAccountNumber parameter to identify the account to which the database must apply the operations, so we include these parameters in the class diagram of Fig. 6.36. In addition, operations credit and debit each require a Double parameter amount to specify the amount of money to be credited or debited, respectively.
The class diagram in Fig. 6.37 models the parameters of class Account's operations. Operation validatePIN requires only a userPIN parameter, which contains the user-specified PIN to be compared with the PIN associated with the account. Like their counterparts in class BankDatabase, operations credit and debit in class Account each require a Double parameter amount that indicates the amount of money involved in the operation. Operations getAvailableBalance and getTotalBalance in class Account require no additional data to perform their tasks. Note that class Account's operations do not require an account number parametereach of these operations can be invoked only on a specific Account object, so including a parameter to specify an Account is unnecessary.
Figure 6.37. Class Account with operation parameters.
(This item is displayed on page 303 in the print version)
Figure 6.38 models class Screen with a parameter specified for operation displayMessage. This operation requires only a String parameter message that indicates the text to be displayed. Recall that the parameter types listed in our class diagrams are in UML notation, so the String type listed in Fig. 6.38 refers to the UML type. When we implement the system in C++, we will in fact use a C++ string object to represent this parameter.
Figure 6.38. Class Screen with operation parameters.
The class diagram in Fig. 6.39 specifies that operation dispenseCash of class CashDispenser takes a Double parameter amount to indicate the amount of cash (in dollars) to be dispensed. Operation isSufficientCashAvailable also takes a Double parameter amount to indicate the amount of cash in question.
Figure 6.39. Class CashDispenser with operation parameters.
Note that we do not discuss parameters for operation execute of classes BalanceInquiry, Withdrawal and Deposit, operation getInput of class Keypad and operation isEnvelopeReceived of class DepositSlot. At this point in our design process, we cannot determine whether these operations require additional data to perform their tasks, so we leave their parameter lists empty. As we progress through the case study, we may decide to add parameters to these operations.
In this section, we have determined many of the operations performed by the classes in the ATM system. We have identified the parameters and return types of some of the operations. As we continue our design process, the number of operations belonging to each class may varywe might find that new operations are needed or that some current operations are unnecessaryand we might determine that some of our class operations need additional parameters and different return types.
Software Engineering Case Study Self-Review Exercises
Which of the following is not a behavior?
obtaining input from the user
If you were to add to the ATM system an operation that returns the amount attribute of class Withdrawal, how and where would you specify this operation in the class diagram of Fig. 6.35?
Describe the meaning of the following operation listing that might appear in a class diagram for an object-oriented design of a calculator:
add( x : Integer, y : Integer ) : Integer
Answers to Software Engineering Case Study Self-Review Exercises
To specify an operation that retrieves the amount attribute of class Withdrawal, the following operation would be placed in the operation (i.e., third) compartment of class Withdrawal:
This is an operation named add that takes integers x and y as parameters and returns an integer value.