In this segment, I will talk about designing classes and show the various differences between Object Oriented & Procedural Programming.
Table of Contents
Abstracting & Encapsulating Classes
To make programming easier for programmers, classes are separated their implementation from how the classes are used or made to function. This is called Class abstraction.
The “fine-details” or “inner processes” of a class’s implementation are hidden from a user, because he does not need to know how the class is implemented. This is called Class encapsulation.
Let me give you an example that shows you how useful class encapsulation is. Let’s say that you made a circle object. Class encapsulation enables you to find the area of this circle object without knowing how the area is computed.
Another example is when you build a computer from parts you buy from online. You don’t need to know exactly how every single component works (class encapsulation). And you only need a general idea of what each part does so that you can put it together (class abstraction) i.e. motherboard connects everything, video card is responsible for the video, network card is responsible for connecting to the internet, cpu is the “brain” of the computer, etc.
So class abstraction is simplification of how a class is to be used. And class encapsulation is hiding the fine details of how a class works.
Loan Example
In this example we will be deconstructing loans to learn about class abstraction & encapsulation.
A loan can be seen as an object of the Loan
class.
The data properties would consist of the interest rate, the amount loaned, the time period of the loan, etc.
The methods would be the process of computing the monthly and total payments for the loan.
So let’s say that you buy a car. A loan object is made from instantiating the Loan
class. The Loan
class is composed of the interest rate, the size of the loan, and the how long the loan lasts.
After that, you can use the methods to calculate the monthly and total payments for your loan. And you are not required to know the detail of how the methods works as a user of the Loan
class.
Below I will be showing a program that calculates loan payments. Note that because the code for calculating the loan payments is in the main method, the program currently cannot reuse this code.
But defining the static methods for evaluating the monthly and total loan payments fixes the problem mentioned above.
But again, defining static methods is only a limited solution. It’s limitations show when you try to associate a date with the loan. Then you are forced to use objects to connect a date with a loan payment.
As you can see in Java, Object Oriented programming is focused on objects that are defined by actions and data inside the object. To contrast, Procedural programming is driven by actions which are separated from its data.
Loan Class Encapsulation via UML
So to tie together a date with a loan, you can make the loan class have the date and the loan’s properties in data fields. In this way, a loan object contains data and actions needed to process the data while at the same time integrating the loan data and actions into one object. With this in mind, here is how the UML diagram looks for the Loan
class:
Notice that we don’t know or see the code of the actual Loan
class. But we can use a UML diagram to symbolize what is in the Loan
class. In this way, we are “Encapsulating” the Loan
class for the user.
Testing the Encapsulated Loan Class
The Loan
class UML diagram right above can be used in place of the actual Loan
class code. The UML can be used in place of the Loan
class code to develop a Java program that tests the Loan
class, which you can see down below:
import java.util.Scanner; public class TestLoanClass { //Main Method public static void main(String[] args) { // Make a Scanner Object Scanner input = new Scanner(System.in); // Enter the yearly interest rate System.out.print("Enter the yearly interest rate, for example, 8.25: "); double yearlyInterestRate = input.nextDouble(); // Enter the number of years System.out.print ("Enter the number of years as an integer: "); int yearDuration = input.nextInt(); // Enter the loan amount System.out.print("Enter the loan amount, for example, 120000.95: "); double loanSize = input.nextDouble(); // Make the Loan object Loan loan = new Loan(yearlyInterestRate, yearDuration, loanSize); // Display loan date, monthly payment, and total payment System.out.printf("The loan was made on %s\n" + "The monthly payment is %.2f\nThe total payment is %.2f\n", loan.fetchLoanTime().toString(), loan.fetchMonthlyPayment(), loan.fetchTotalPayment()); } }
Output:
So you can see that the main
method reads the interest rate, the duration of the payment, and the loan size. The main
method also makes the Loan
object, fetches the payment per month, and the total payment via the usage of the instance method in the Loan
class.
Extra Notes:
printf
allows you to format what you are printing out to the console.- The
%
character automatically substitutes with a value. %.2f
syntax tells Java to return your variablewith 2 decimal places
.2
in decimal representation of a floating-point numberf
from the start of the format specifier%
.- The use of
%s
will result in thetoString()
method being called on the object.
Now down below I will show you the code that makes up the Loan
class.
Revealing the Loan Class (un-encapsulated)
Above, I showed a UML diagram that acted to “encapsulate” or hide the Loan
Class. Even though you didn’t see in detail what the Loan
Class is, you are still able to test the Loan
Class by using the UML. Down below, I will show you the “details” that I’ve previously encapsulated from the Loan
Class.
public class Loan { private double yearlyInterestRate; private int yearDuration; private double loanSize; private java.util.Date loanTime; //The Default Constructor for the Loan Class public Loan() { this(2.5, 1, 1000); } // Construct a loan with a specified yearly interest rate, duration, and loan size public Loan(double yearlyInterestRate, int yearDuration, double loanSize) { this.yearlyInterestRate = yearlyInterestRate; this.yearDuration = yearDuration; this.loanSize = loanSize; loanTime = new java.util.Date(); } // Return the Yearly Interest Rate public double fetchYearlyInterestRate() { return yearlyInterestRate; } // Return the duration of the loan public int fetchYearDuration() { return yearDuration; } // Return the size of the loan public double fetchLoanSize() { return loanSize; } // Return the time when the loan was taken public java.util.Date fetchLoanTime() { return loanTime; } // Set a yearly interest rate public void setYearlyInterestRate(double yearlyInterestRate) { this.yearlyInterestRate = yearlyInterestRate; } // Set the loan duration public void setYearDuration(int yearDuration) { this.yearDuration = yearDuration; } // Set the size of the loan public void setLoanSize(double loanSize) { this.loanSize = loanSize; } // Find and Calculate the monthly payment to return public double fetchMonthlyPayment() { double monthlyInterestRate = yearlyInterestRate / 1200; double monthlyPayment = loanSize * monthlyInterestRate / (1 - (1/ Math.pow(1 + monthlyInterestRate, yearDuration * 12))); return monthlyPayment; } // Find and Calculate the total payment public double fetchTotalPayment() { double totalPayment = fetchMonthlyPayment() * yearDuration * 12; return totalPayment; } }
So I want to drive home a few points through this exercise. First, Java programmers has to design their programs/classes to be encapsulated and abstract, so that their team members can quickly understand what the program/class does and build upon it, and so that clients can use the Java application without much knowledge about how the program/class works and instead given a simple explanation that they can understand quickly.
To show the usefulness of class encapsulation & abstraction, let’s take into consideration the output of the testClassLoan.java program. Imagine that the client or user only sees is what is in the console; none of the code. The console asks the user to input the yearly interest rate, the number of years the loan lasts, and the size of the loan- which is easily understood by the client/user. After executing the program the client receives information on the current time that the loan was made and what the monthly & total payments are- all without needing to know what made the program work.
Let me finish by saying that the purpose of abstraction & encapsulation is to improve the usability and flexibility of a class or program.
◄◄◄BACK | NEXT►►►