The key to object-oriented programming is to model the application in terms of cooperative objects. Carefully designed classes are critical when a project is being developed. There are many levels of abstraction in system design. You have learned method abstraction and have applied it to the development of large programs. Methods are means to group statements. Classes extend abstraction to a higher level and provide a means of grouping methods . Classes do more than just group methods, however; they also contain data fields. Methods and data fields together describe the properties and behaviors of classes.
The power of classes is further extended by inheritance. Inheritance enables a class to extend the contract and the implementation of an existing class without knowing the details of the existing class. In the development of a Java program, class abstraction is applied to decompose the problem into a set of related classes, and method abstraction is applied to design individual classes.
This case study models borrowing loans to demonstrate how to identify classes, discover the relationships between classes, and apply class abstraction in object-oriented program development.
For simplicity, the example does not attempt to build a complete system for storing, processing, and manipulating loans for borrowers; instead it focuses on modeling borrowers and the loans for the borrowers. The following steps are usually involved in building an object-oriented system:
1. | Identify classes for the system. |
2. | Establish relationships among classes. |
3. | Describe the attributes and methods in each class. |
4. | Implement the classes. |
The first step is to identify classes for the system. There are many strategies for identifying classes in a system, one of which is to study how the system works and select a number of use cases, or scenarios. Since a borrower is a person who obtains a loan, and a person has a name and an address, you can identify the following classes: Person , Name , Address , Borrower , and Loan .
Identifying objects is not easy for novice programmers. How do you find the right objects? There is no unique solution even for simple problems. Software development is more an art than a science. The quality of a program ultimately depends on the programmer's intuition, experience, and knowledge. This example identifies five classes: Name , Address , Person , Borrower , and Loan . There are several alternatives. One would combine Name , Address , Person , and Borrower into one class. This design is not clear because it puts too many entities into one class.
The second step is to establish relationships among the classes. The relationship is derived from the system analysis. The first two steps are intertwined. When you identify classes, you also think about the relationships among them. Establishing relationships among objects helps you understand the interactions among objects. An object-oriented system consists of a collection of interrelated cooperative objects. The relationships for the classes in this example are illustrated in Figure 11.9.
The third step is to describe the attributes and methods in each of the classes you have identified. The Name class has the properties firstName , mi , and lastName , their associated get and set methods, and the getFullName method for returning the full name. You can compare names in alphabetical order of their last name, first name, and mi. The Address class has the properties street , city , state , and zip , their associated get and set methods, and the getAddress method for returning the full address. The Loan class, presented in Listing 7.9, Loan.java, has the properties annualInterestRate , numberOfYears , and loanAmount , their associated property get and set methods, and getMonthlyPayment and getTotalPayment methods. The Person class has the properties name and address , their associated get and set methods, and the toString method for displaying complete information about the person. Borrower is a subclass of Person . Additionally, Borrower has the loan property and its associated get and set methods, and the toString method for displaying the person and the loan payments. You can compare persons according to their names. Figure 11.9 is expanded to Figure 11.10.
The fourth step is to write the code for the classes. The program is long, but most of the coding is for the get and set methods. Once an object is identified, its properties and methods can be defined by analyzing the requirements and scenarios of the system. It is a good practice to provide complete get and set methods. These may not be needed for your current project, but will be useful in other projects, because your classes are designed for reuse in future projects. Listings 11.1, 11.2, 11.3, and 11.4 give the Name , Address , Person , and Borrower classes.
1 public final class Name implements Comparable { 2 private String firstName; 3 private char mi; 4 private String lastName; 5 6 /** Construct a name with firstName, mi, and lastName */ 7 public Name(String firstName, char mi, String lastName) { 8 this .firstName = firstName; 9 this .mi = mi; 10 this .lastName = lastName; 11 } 12 13 /** Return firstName */ 14 public String getFirstName() { 15 return firstName; 16 } 17 18 /** Return middle name initial */ 19 public char getMi() { 20 return mi; 21 } 22 23 /** Return lastName */ 24 public String getLastname() { 25 return lastName; 26 } 27 28 /** Obtain full name */ 29 public String getFullName() { 30 return firstName + ' ' + mi + ' ' + lastName; 31 } 32 33 /** Implement compareTo in the Comparable interface */ 34 public int compareTo(Object o) { 35 if (!lastName.equals(((Name)o).lastName)) { 36 return lastName.compareTo(((Name)o).lastName); 37 } 38 else if (!firstName.equals(((Name)o).firstName)) { 39 return firstName.compareTo(((Name)o).firstName); 40 } 41 else { 42 return mi - ((Name)o).mi; 43 } 44 } 45 } |
1 public final class Address { 2 private String street; 3 private String city; 4 private String state; 5 private String zip; 6 7 /** Create an address with street, city, state, and zip */ 8 public Address(String street, String city, 9 String state, String zip) { 10 this .street = street; 11 this .city = city; 12 this .state = state; 13 this .zip = zip; 14 } 15 16 /** Return street */ 17 public String getStreet() { 18 return street; 19 } 20 21 /** Return city */ 22 public String getCity() { 23 return city; 24 } 25 26 /** Return state */ 27 public String getState() { 28 return state; 29 } 30 31 /** Return zip */ 32 public String getZip() { 33 return zip; 34 } 35 36 /** Get full address */ 37 public String getFullAddress() { 38 return street + '\n' + city + ", " + state + ' ' + zip + '\n' ; 39 } 40 } |
1 public class Person { 2 private Name name; 3 private Address address; 4 5 /** Construct a person with default properties */ 6 public Person() { 7 this ( new Name( "Jill" , 'S' , "Barr" ), 8 new Address( "100 Main" , "Savannah" , "GA" , "31411" )); 9 } 10 11 /** Construct a person with specified name and address */ 12 public Person(Name name, Address address) { 13 this .name = name; 14 this .address = address; 15 } 16 17 /** Return name */ 18 public Name getName() { 19 return name; 20 } 21 22 /** Set a new name */ 23 public void setName(Name name) { 24 this .name = name; 25 } 26 27 /** Return address */ 28 public Address getAddress() { 29 return address; 30 } 31 32 /** Set a new address */ 33 public void setAddress(Address address) { 34 this .address = address; 35 } 36 37 /** Override the toString method */ 38 public String toString() { 39 return '\n' + name.getFullName() + '\n' + 40 address.getFullAddress() + '\n' ; 41 } 42 43 /** Implement compareTo in the Comparable interface */ 44 public int compareTo(Object o) { 45 return name.compareTo(((Person)o).name); 46 } 47 } |
1 public class Borrower extends Person { 2 private Loan loan; 3 4 /** Construct a borrower with default properties */ 5 public Borrower() { 6 super (); 7 } 8 9 /** Create a borrower with specified name and address */ 10 public Borrower(Name name, Address address) { 11 super (name, address); 12 } 13 14 /** Return loan */ 15 public Loan getLoan() { 16 return loan; 17 } 18 19 /** Set a new loan */ 20 public void setLoan(Loan loan) { 21 this .loan = loan; 22 } 23 24 /** String representation for borrower */ 25 public String toString() { 26 return super .toString() + 27 "Monthly payment is " + loan.getMonthlyPayment() + '\n' + 28 "Total payment is " + loan.getTotalPayment(); 29 } 30 } |
Listing 11.5 is a test program that uses the classes Name , Address , Borrower , and Loan . The output of the program is shown in Figure 11.11.
1 import javax.swing.JOptionPane; 2 3 public class BorrowLoan { 4 /** Main method */ 5 public static void main(String[] args) { 6 // Create a name 7 Name name = new Name( "John" , 'D' , "Smith" ); 8 9 // Create an address 10 Address address = new Address( "100 Main Street" , "Savannah" , 11 "GA" , "31419" ); 12 13 // Create a loan 14 Loan loan = new Loan( 5 . 5 , 15 , 250000 ); 15 16 // Create a borrower 17 Borrower borrower = new Borrower(name, address); 18 19 borrower.setLoan(loan); 20 21 // Display loan information 22 JOptionPane.showMessageDialog( null , borrower.toString()); 23 } 24 } |