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'll 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 object states and modeled object
state transitions and activities. Now, we determine some of the class operations
(or behaviors) needed to implement the ATM system.
Identifying Operations
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 well—for 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
specification. We then relate each of these to particular classes in our system
(Fig. 6.32). The
verb phrases in Fig.
6.32 help us determine the operations of each
class.
Fig. 6.32. Verbs and verb phrases for each class in the
ATM system.
| Class |
Verbs and verb phrases |
| ATM |
executes financial
transactions |
| BalanceInquiry |
[none in the requirements
specification] |
| Withdrawal |
[none in the requirements
specification] |
| Deposit |
[none in the requirements
specification] |
| BankDatabase |
authenticates a user, retrieves an account balance,
credits a deposit amount to an account, debits a withdrawal amount from an
account |
| Account |
retrieves an account balance, credits a deposit amount
to an account, debits a withdrawal amount from an account |
| Screen |
displays a
message to the user |
| Keypad |
receives
numeric input from the user |
| CashDispenser |
dispenses
cash, indicates whether it contains enough cash to satisfy a withdrawal
request |
| DepositSlot |
receives a deposit
envelope |
Modeling Operations
To create the updated class
diagram of Fig.
6.33, we first identify operations by examining the
verb phrases listed for each class in Fig. 6.32. 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 class diagram of Fig. 6.33.
During an ATM session, the ATM object will invoke the
execute operation of each transaction
object to tell it to execute.
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 operations—we'll identify and model the parameters of some of
the operations shortly. For some, 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'll add the remaining return
types.
Operations of Class BankDatabase and Class Account
Figure
6.32 lists the phrase "authenticates a user" next to class
BankDatabase—the 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.33). 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.32 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'll 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
balance—availableBalance 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.33). 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 specification 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 specification
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.33). Note that we do not worry about the parameter of this
operation at this time—we 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.32, we conclude that class
Keypad should perform a getInput operation. Because the ATM's
keypad, unlike a computer
keyboard, contains only the numbers 0–9, we specify that this operation returns
an integer value. Recall from the requirements specification 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 class—it 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'll see how to examine inputs
to determine if they are of particular types.]
Operations of Class CashDispenser and Class DepositSlot
Figure
6.32 lists "dispenses cash" for class CashDispenser. Therefore, we
create operation dispenseCash and list it under class
CashDispenser in Fig. 6.33. 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.32 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 operations—we 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.34
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 the parameters to
save space. Remember, however, that the operations listed in these diagrams
still have 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.34 thus specifies that operation authenticateUser
takes two parameters—userAccountNumber and userPIN, both of type Integer. When we
implement the system in C++, we'll 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.34. 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.35 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
parameter—each of these operations can be invoked only on a specific
Account object, so including a parameter to
specify an Account is unnecessary.

Figure 6.36 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.36
refers to the UML type. When we implement the system in C++, we'll in fact use a
C++ string object to represent this parameter.

The class diagram in Fig. 6.37 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.

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 vary—we
might find that new operations are needed or that some current operations are
unnecessary—and we might determine that some of our class operations need
additional parameters and different return types.
Software Engineering Case Study
Self-Review Exercises
| 6.1 |
Which of the following is not a
behavior?
-
-
-
-
obtaining input from the
user |
| 6.2 |
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.33? |
|
|
| 6.3 |
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
| 6.1 |
c. |
| 6.2 |
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:
|
| 6.3 |
This is an operation named add
that takes integers x and y as
parameters and returns an integer value. |