(Optional) Software Engineering Case Study: Incorporating Inheritance and Polymorphism into the ATM System

(Optional) Software Engineering Case Study Incorporating Inheritance and Polymorphism into the ATM System

We now revisit our ATM system design to see how it might benefit from inheritance and polymorphism. To apply inheritance, we first look for commonality among classes in the system. We create an inheritance hierarchy to model similar classes in an elegant and efficient manner that enables us to process objects of these classes polymorphically. We then modify our class diagram to incorporate the new inheritance relationships. Finally, we demonstrate how the inheritance aspects of our updated design are translated into C# code.

In Section 4.11, we encountered the problem of representing a financial transaction in the system. Rather than create one class to represent all transaction types, we created three distinct transaction classesBalanceInquiry, Withdrawal and Depositto represent the transactions that the ATM system can perform. The class diagram of Fig. 11.19 shows the attributes and operations of these classes. Note that they have one private attribute (accountNumber) and one public operation (Execute) in common. Each class requires attribute accountNumber to specify the account to which the transaction applies. Each class contains operation Execute, which the ATM invokes to perform the transaction. Clearly, BalanceInquiry, Withdrawal and Deposit represent types of transactions. Figure 11.19 reveals commonality among the transaction classes, so using inheritance to factor out the common features seems appropriate for designing these classes. We place the common functionality in base class transaction and derive classes BalanceInquiry, Withdrawal and Deposit from transaction (Fig. 11.20).

Figure 11.19. Attributes and operations of classes BalanceInquiry, Withdrawal and Deposit.

Figure 11.20. Class diagram modeling the generalization (i.e., inheritance) relationship between the base class transaction and its derived classes BalanceInquiry, Withdrawal and Deposit.

The UML specifies a relationship called a generalization to model inheritance. Figure 11.20 is the class diagram that models the inheritance relationship between base class transaction and its three derived classes. The arrows with triangular hollow arrowheads indicate that classes BalanceInquiry, Withdrawal and Deposit are derived from class transaction by inheritance. Class transaction is said to be a generalization of its derived classes. The derived classes are said to be specializations of class TRansaction.

As Fig. 11.19 shows, classes BalanceInquiry, Withdrawal and Deposit share private int attribute accountNumber. We'd like to factor out this common attribute and place it in the base class TRansaction. However, recall that a base class's private attributes are not accessible in derived classes. The derived classes of TRansaction require access to attribute accountNumber so that they can specify which Account to process in the BankDatabase. As you learned in Chapter 10, a derived class can access only the public, protected and protected internal members of its base class. However, the derived classes in this case do not need to modify attribute accountNumberthey need only to access its value. For this reason, we have chosen to replace private attribute accountNumber in our model with the public read-only property AccountNumber. Since this is a read-only property, it provides only a get accessor to access the account number. Each derived class inherits this property, enabling the derived class to access its account number as needed to execute a transaction. We no longer list accountNumber in the second compartment of each derived class, because the three derived classes inherit property AccountNumber from transaction.

According to Fig. 11.19, classes BalanceInquiry, Withdrawal and Deposit also share operation Execute, so base class transaction should contain public operation Execute. However, it does not make sense to implement Execute in class transaction, because the functionality that this operation provides depends on the specific type of the actual transaction. We therefore declare Execute as an abstract operation in base class transactionit will become an abstract method in the C# implementation. This makes transaction an abstract class and forces any class derived from transaction that must be a concrete class (i.e., BalanceInquiry, Withdrawal and Deposit) to implement the operation Execute to make the derived class concrete. The UML requires that we place abstract class names and abstract operations in italics. Thus, in Fig. 11.20, transaction and Execute appear in italics for the transaction class; Execute is not italicized in derived classes BalanceInquiry, Withdrawal and Deposit. Each derived class overrides base class transaction's Execute operation with an appropriate concrete implementation. Note that Fig. 11.20 includes operation Execute in the third compartment of classes BalanceInquiry, Withdrawal and Deposit, because each class has a different concrete implementation of the overridden operation.

As you learned in this chapter, a derived class can inherit interface and implementation from a base class. Compared to a hierarchy designed for implementation inheritance, one designed for interface inheritance tends to have its functionality lower in the hierarchya base class signifies one or more operations that should be defined by each class in the hierarchy, but the individual derived classes provide their own implementations of the operation(s). The inheritance hierarchy designed for the ATM system takes advantage of this type of inheritance, which provides the ATM with an elegant way to execute all transactions "in the general" (i.e., polymorphically). Each class derived from transaction inherits some implementation details (e.g., property AccountNumber), but the primary benefit of incorporating inheritance into our system is that the derived classes share a common interface (e.g., abstract operation Execute). The ATM can aim a TRansaction reference at any transaction, and when the ATM invokes the operation Execute through this reference, the version of Execute specific to that transaction runs (polymorphically) automatically (due to polymorphism). For example, suppose a user chooses to perform a balance inquiry. The ATM aims a transaction reference at a new object of class BalanceInquiry, which the C# compiler allows because a BalanceInquiry is a transaction. When the ATM uses this reference to invoke Execute, BalanceInquiry's version of Execute is called (polymorphically).

This polymorphic approach also makes the system easily extensible. Should we wish to create a new transaction type (e.g., funds transfer or bill payment), we would simply create an additional TRansaction derived class that overrides the Execute operation with a version appropriate for the new transaction type. We would need to make only minimal changes to the system code to allow users to choose the new transaction type from the main menu and for the ATM to instantiate and execute objects of the new derived class. The ATM could execute transactions of the new type using the current code, because it executes all transactions identically (through polymorphism).

As you learned earlier in the chapter, an abstract class like transaction is one for which the programmer never intends to (and, in fact, cannot) instantiate objects. An abstract class simply declares common attributes and behaviors for its derived classes in an inheritance hierarchy. Class TRansaction defines the concept of what it means to be a transaction that has an account number and can be executed. You may wonder why we bother to include abstract operation Execute in class TRansaction if Execute lacks a concrete implementation. Conceptually, we include this operation because it is the defining behavior of all transactionsexecuting. Technically, we must include operation Execute in base class transaction so that the ATM (or any other class) can invoke each derived class's overridden version of this operation polymorphically via a transaction reference.

Derived classes BalanceInquiry, Withdrawal and Deposit inherit property AccountNumber from base class transaction, but classes Withdrawal and Deposit contain the additional attribute amount that distinguishes them from class BalanceInquiry. Classes Withdrawal and Deposit require this additional attribute to store the amount of money that the user wishes to withdraw or deposit. Class BalanceInquiry has no need for such an attribute and requires only an account number to execute. Even though two of the three TRansaction derived classes share the attribute amount, we do not place it in base class TRansactionwe place only features common to all the derived classes in the base class, so derived classes do not inherit unnecessary attributes (and operations).

Figure 11.21 presents an updated class diagram of our model that incorporates inheritance and introduces abstract base class transaction. We model an association between class ATM and class TRansaction to show that the ATM, at any given moment, either is executing a transaction or is not (i.e., zero or one objects of type transaction exist in the system at a time). Because a Withdrawal is a type of TRansaction, we no longer draw an association line directly between class ATM and class Withdrawalderived class Withdrawal inherits base class TRansaction's association with class ATM. Derived classes BalanceInquiry and Deposit also inherit this association, which replaces the previously omitted associations between classes BalanceInquiry and Deposit, and class ATM. Note again the use of triangular hollow arrowheads to indicate the specializations (i.e., derived classes) of class transaction, as indicated in Fig. 11.20.

Figure 11.21. Class diagram of the ATM system (incorporating inheritance). Note that abstract class name TRansaction appears in italics.

(This item is displayed on page 552 in the print version)

We also add an association between class transaction and the BankDatabase (Fig. 11.21). All TRansactions require a reference to the BankDatabase so that they can access and modify account information. Each TRansaction derived class inherits this reference, so we no longer model the association between class Withdrawal and the BankDatabase. Note that the association between class transaction and the BankDatabase replaces the previously omitted associations between classes BalanceInquiry and Deposit, and the BankDatabase.

We include an association between class transaction and the Screen because all transactions display output to the user via the Screen. Each derived class inherits this association. Therefore, we no longer include the association previously modeled between Withdrawal and the Screen. Class Withdrawal still participates in associations with the CashDispenser and the Keypad, howeverthese associations apply to derived class Withdrawal but not to derived classes BalanceInquiry and Deposit, so we do not move these associations to base class transaction.

Our class diagram incorporating inheritance (Fig. 11.21) also models classes Deposit and BalanceInquiry. We show associations between Deposit and both the DepositSlot and the Keypad. Note that class BalanceInquiry takes part in only those associations inherited from class transactiona BalanceInquiry interacts only with the BankDatabase and the Screen.

The class diagram of Fig. 9.23 showed attributes, properties and operations with visibility markers. Now we present a modified class diagram in Fig. 11.22 that includes abstract base class transaction. This abbreviated diagram does not show inheritance relationships (these appear in Fig. 11.21), but instead shows the attributes and operations after we have employed inheritance in our system. Note that abstract class name transaction and abstract operation name Execute in class transaction appear in italics. To save space, as we did in Fig. 5.19, we do not include those attributes shown by associations in Fig. 11.21we do, however, include them in the C# implementation in Appendix J. We also omit all operation parameters, as we did in Fig. 9.23incorporating inheritance does not affect the parameters already modeled in Figs. 7.227.25.

Figure 11.22. Class diagram after incorporating inheritance into the system.

Software Engineering Observation 11 12

A complete class diagram shows all the associations among classes, and all the attributes and operations for each class. When the number of class attributes, operations and associations is substantial (as in Figs. 11.21 and 11.22), a good practice that promotes readability is to divide this information between two class diagramsone focusing on associations and the other on attributes and operations. When examining classes modeled in this fashion, it is crucial to consider both class diagrams to get a complete picture of the classes. For example, one must refer to Fig. 11.21 to observe the inheritance relationship between transaction and its derived classes; that relationship is omitted from Fig. 11.22.

 

Implementing the ATM System Design Incorporating Inheritance

In Section 9.17, we began implementing the ATM system design in C# code. We now modify our implementation to incorporate inheritance, using class Withdrawal as an example.

  1. If a class A is a generalization of class B, then class B is derived from (and is a specialization of) class A. For example, abstract base class transaction is a generalization of class Withdrawal. Thus, class Withdrawal is derived from (and is a specialization of) class TRansaction. Figure 11.23 contains the shell of class Withdrawal, in which the class definition indicates the inheritance relationship between Withdrawal and TRansaction (line 3).
  2. If class A is an abstract class and class B is derived from class A, then class B must implement the abstract operations of class A if class B is to be a concrete class. For example, class transaction contains abstract operation Execute, so class Withdrawal must implement this operation if we want to instantiate Withdrawal objects. Figure 11.24 contains the portions of the C# code for class Withdrawal that can be inferred from Fig. 11.21 and Fig. 11.22. Class Withdrawal inherits property AccountNumber from base class transaction, so Withdrawal does not declare this property. Class Withdrawal also inherits references to the Screen and the BankDatabase from class transaction, so we do not include these references in our code. Figure 11.22 specifies attribute amount and operation Execute for class Withdrawal. Line 6 of Fig. 11.24 declares an instance variable for attribute amount. Lines 1720 declare the shell of a method for operation Execute. Recall that derived class Withdrawal must provide a concrete implementation of the abstract method Execute from base class transaction. The keypad and cashDispenser references (lines 78) are instance variables whose need is apparent from class Withdrawal's associations in Fig. 11.21in the C# implementation of this class in Appendix J, a constructor initializes these references to actual objects.

Figure 11.23. C# code for shell of class Withdrawal.

1 // Fig 11.23: Withdrawal.cs
2 // Class Withdrawal represents an ATM withdrawal transaction.
3 public class Withdrawal : Transaction
4 {
5 // code for members of class Withdrawal
6 } // end class Withdrawal

Figure 11.24. C# code for class Withdrawal based on Fig. 11.21 and Fig. 11.22.

 1 // Fig 11.24: Withdrawal.cs
 2 // Class Withdrawal represents an ATM withdrawal transaction.
 3 public class Withdrawal : Transaction
 4 {
 5 // attributes
 6 private decimal amount; // amount to withdraw
 7 private Keypad keypad; // reference to keypad
 8 private CashDispenser cashDispenser; // reference to cash dispenser
 9
10 // parameterless constructor
11 public Withdrawal()
12 {
13 // constructor body code
14 } // end constructor
15 16 // method that overrides Execute 17 public override void Execute() 18 { 19 // Execute method body code 20 } // end method Execute 21 } // end class Withdrawal

We discuss the polymorphic processing of TRansactions in Section J.2 of the ATM implementation. Class ATM performs the actual polymorphic call to method Execute at line 99 of Fig. J.1.

ATM Case Study Wrap-Up

This concludes our object-oriented design of the ATM system. A complete C# implementation of the ATM system in 655 lines of code appears in Appendix J. This working implementation uses most of the key object-oriented programming concepts that we have covered to this point in the book, including classes, objects, encapsulation, visibility, composition, inheritance and polymorphism. The code is abundantly commented and conforms to the coding practices you've learned so far. Mastering this code is a wonderful capstone experience for you after studying the nine Software Engineering Case Study sections in Chapters 1, 39 and 11.

Software Engineering Case Study Self-Review Exercises

11.1

The UML uses an arrow with a __________ to indicate a generalization relationship.

  1. solid filled arrowhead
  2. triangular hollow arrowhead
  3. diamond-shaped hollow arrowhead
  4. stick arrowhead
11.2

State whether the following statement is true or false, and if false, explain why: The UML requires that we underline abstract class names and abstract operation names.

11.3

Write C# code to begin implementing the design for class transaction specified in Fig. 11.21 and Fig. 11.22. Be sure to include private references based on class TRansaction's associations. Also, be sure to include properties with public get accessors for any of the private instance variables that the derived classes must access to perform their tasks.

Answers to Software Engineering Case Study Self-Review Exercises

11.1

b.

11.2

False. The UML requires that we italicize abstract class names and operation names.

11.3

The design for class transaction yields the code in Fig. 11.25. In the implementation in Appendix J, a constructor initializes private instance variables userScreen and database to actual objects, and read-only properties UserScreen and Database access these instance variables. These properties allow classes derived from transaction to access the ATM's screen and interact with the bank's database. Note that we chose the names of the UserScreen and Database properties for claritywe wanted to avoid property names that are the same as the class names Screen and BankDatabase, which can be confusing.

Figure 11.25. C# code for class TRansaction based on Fig. 11.21 and Fig. 11.22.

 1 // Fig 11.25: Transaction.cs
 2 // Abstract base class Transaction represents an ATM transaction.
 3 public abstract class Transaction
 4 {
 5 private int accountNumber; // indicates account involved
 6 private Screen userScreen; // ATM's screen
 7 private BankDatabase database; // account info database
 8
 9 // parameterless constructor
10 public Transaction()
11 {
12 // constructor body code
13 } // end constructor
14
15 // read-only property that gets the account number
16 public int AccountNumber
17 {
18 get
19 {
20 return accountNumber;
21 } // end get
22 } // end property AccountNumber
23
24 // read-only property that gets the screen reference
25 public Screen UserScreen
26 {
27 get
28 {
29 return userScreen;
30 } // end get
31 } // end property UserScreen
32
33 // read-only property that gets the bank database reference
34 public BankDatabase Database
35 {
36 get
37 {
38 return database;
39 } // end get
40 } // end property Database
41
42 // perform the transaction (overridden by each derived class)
43 public abstract void Execute();
44 } // end class Transaction

Preface

Index

    Introduction to Computers, the Internet and Visual C#

    Introduction to the Visual C# 2005 Express Edition IDE

    Introduction to C# Applications

    Introduction to Classes and Objects

    Control Statements: Part 1

    Control Statements: Part 2

    Methods: A Deeper Look

    Arrays

    Classes and Objects: A Deeper Look

    Object-Oriented Programming: Inheritance

    Polymorphism, Interfaces & Operator Overloading

    Exception Handling

    Graphical User Interface Concepts: Part 1

    Graphical User Interface Concepts: Part 2

    Multithreading

    Strings, Characters and Regular Expressions

    Graphics and Multimedia

    Files and Streams

    Extensible Markup Language (XML)

    Database, SQL and ADO.NET

    ASP.NET 2.0, Web Forms and Web Controls

    Web Services

    Networking: Streams-Based Sockets and Datagrams

    Searching and Sorting

    Data Structures

    Generics

    Collections

    Appendix A. Operator Precedence Chart

    Appendix B. Number Systems

    Appendix C. Using the Visual Studio 2005 Debugger

    Appendix D. ASCII Character Set

    Appendix E. Unicode®

    Appendix F. Introduction to XHTML: Part 1

    Appendix G. Introduction to XHTML: Part 2

    Appendix H. HTML/XHTML Special Characters

    Appendix I. HTML/XHTML Colors

    Appendix J. ATM Case Study Code

    Appendix K. UML 2: Additional Diagram Types

    Appendix L. Simple Types

    Index



    Visual C# How to Program
    Visual C# 2005 How to Program (2nd Edition)
    ISBN: 0131525239
    EAN: 2147483647
    Year: 2004
    Pages: 600

    Flylib.com © 2008-2020.
    If you may any questions please contact us: flylib@qtcs.net