Class abstraction is the separation of class implementation from the use of a class. The details of implementation are encapsulated and hidden from the user. This is known as class encapsulation. Java provides many levels of abstraction, and class abstraction separates class implementation from how the class is used. The creator of a class describes the functions of the class and lets the user know how the class can be used. The collection of methods and fields that are accessible from outside the class, together with the description of how these members are expected to behave, serves as the class’s contract. As shown in Figure below, the user of the class does not need to know how the class is implemented.
The details of implementation are encapsulated and hidden from the user. This is called class encapsulation. For example, you can create a Circle object and find the area of the circle without knowing how the area is computed. For this reason, a class is also known as an abstract data type (ADT).
Class abstraction and encapsulation are two sides of the same coin. Many real-life examples illustrate the concept of class abstraction. Consider, for instance, building a computer system. Your personal computer has many components—a CPU, memory, disk, motherboard, fan, and so on. Each component can be viewed as an object that has properties and methods. To get the components to work together, you need know only how each component is used and how it interacts with the others. You don’t need to know how the components work internally. The internal implementation is encapsulated and hidden from you. You can build a computer without knowing how a component is implemented.
The computer-system analogy precisely mirrors the object-oriented approach. Each component can be viewed as an object of the class for the component. For example, you might have a class that models all kinds of fans for use in a computer, with properties such as fan size and speed and methods such as start and stop. A specific fan is an instance of this class with specific property values.
As another example, consider getting a loan. A specific loan can be viewed as an object of a Loan class. The interest rate, loan amount, and loan period are its data properties, and computing the monthly payment and total payment are its methods. When you buy a car, a loan object is created by instantiating the class with your loan interest rate, loan amount, and loan period. You can then use the methods to find the monthly payment and total payment of your loan. As a user of the Loan class, you don’t need to know how these methods are implemented.
ComputeLoan.java, here presented a program for computing loan payments. That
program cannot be reused in other programs because the code for computing the payments is in the main method. One way to fix this problem is to define static methods for computing the monthly payment and total payment. However, this solution has limitations. Suppose you wish to associate a date with the loan. There is no good way to tie a date with a loan without using objects. The traditional procedural programming paradigm is action-driven, and data are separated from actions. The object-oriented programming paradigm focuses on objects, and actions are defined along with the data in objects. To tie a date with a loan, you can define a loan class with a date along with the loan’s other properties as data fields. A loan object now contains data and actions for manipulating and processing data, and the loan data and actions are integrated in one object. Figure below shows the UML class diagram for the Loan class.
The UML diagram in Figure above serves as the contract for the Loan class. Throughout this book, you will play the roles of both class user and class developer. Remember that a class user can use the class without knowing how the class is implemented. Assume that the Loan class is available. The program below uses that class.
Enter annual interest rate, for example, 8.25: 2.5
Enter number of years as an integer: 5
Enter loan amount, for example, 120000.95: 1000
The loan was created on Sat Jun 16 21:12:50 EDT 2012
The monthly payment is 17.75
The total payment is 1064.84
The main method reads the interest rate, the payment period (in years), and the loan amount; creates a Loan object; and then obtains the monthly payment (line 26) and the total payment (line 26) using the instance methods in the Loan class. The Loan class can be implemented as in below.
package demo;
public class Loan {
private double annualInterestRate;
private int numberOfYears;
private double loanAmount;
private java.util.Date loanDate;
/** Default constructor */
public Loan() {
this(2.5, 1, 1000);
}
/** Construct a loan with specified annual interest rate, number of years, and loan amount */
public Loan(double annualInterestRate, int numberOfYears, double loanAmount) {
this.annualInterestRate = annualInterestRate;
this.numberOfYears = numberOfYears;
this.loanAmount = loanAmount;
loanDate = new java.util.Date();
}
/** Returns annualInterestRate */
public double getAnnualInterestRate() {
return annualInterestRate;
}
/** Set a new annualInterestRate */
public void setAnnualInterestRate(double annualInterestRate) {
this.annualInterestRate = annualInterestRate;
}
/** Return numberOfYears */
public int getNumberOfYears() {
return numberOfYears;
}
/** Set a new numberOFYears */
public void setNumberOfYears(int numberOfYears) {
this.numberOfYears = numberOfYears;
}
/** Return loanAmount */
public double getLoanAmount() {
return loanAmount;
}
/** Set a new loanAmount */
public void setLoanAmount(double loanAmount) {
this.loanAmount = loanAmount;
}
/** Return loanDate */
public java.util.Date getLoanDate() {
return loanDate;
}
/** Find monthly payment */
public double getMonthlyPayment() {
double monthlyInterestRate = annualInterestRate / 1200;
double monthlyPayment = loanAmount * monthlyInterestRate / (1 - (1 / Math.pow(1 + monthlyInterestRate, numberOfYears * 12)));
return monthlyPayment;
}
/** Find total payment */
public double getTotalPayment() {
double totalPayment = getMonthlyPayment() * numberOfYears * 12;
return totalPayment;
}
}
From a class developer’s perspective, a class is designed for use by many different customers. In order to be useful in a wide range of applications, a class should provide a variety of ways for customization through constructors, properties, and methods.
The Loan class contains two constructors, four getter methods, three setter methods, and the methods for finding the monthly payment and the total payment. You can construct a Loan object by using the no-arg constructor or the constructor with three parameters: annual interest rate, number of years, and loan amount. When a loan object is created, its date is stored in the loanDate field. The getLoanDate method returns the date. The methods—getAnnualInterest, getNumberOfYears, and getLoanAmount—return the annual interest rate, payment years, and loan amount, respectively. All the data properties and methods in this class are tied to a specific instance of the Loan class. Therefore, they are instance variables and methods.
Use the UML diagram for the Loan class to write a test program that uses the Loan class even though you don’t know how the Loan class is implemented. This has three benefits:
- It demonstrates that developing a class and using a class are two separate tasks.
- It enables you to skip the complex implementation of certain classes without interrupting the sequence of this book.
- It is easier to learn how to implement a class if you are familiar with it by using the class.
For all the class examples from now on, create an object from the class and try using its methods before turning your attention to its implementation.
Top comments (0)