The Concepts of OOPs

In this article, I will share detailed information about object-oriented programming and talk about OOP basic terminologies and OOP concepts.

OOPs Concepts

What is object-oriented programming? (OOP)

bject-oriented programming is a form of programming that allows programmers to think as if they are working with real-life entities or objects. In real life, people have knowledge and can do a variety of jobs. In OOP, objects have fields to store information/state/data and use methods to do various things.

Basic Terminologies

Object:

It is an instance of a class and is a worker entity.

Class:

It is an outline of what an object can do and its capacity.

Method:

It contains the behaviors of a class. It tells what a method can do.

Instance:

Object and Instance are both the same with a slight difference.

For example: Suppose we have a class named Vehicle. Class is a blueprint that includes fields and methods. All objects created from the Vehicle blueprint create an instance.

The creation of the instance called instantiation.

The Concept of OOP Design

  1. Abstraction
  2. Encapsulation
  3. Inheritance
  4. Polymorphism

Encapsulation

Encapsulation is a mechanism for wrapping data. It allows it to be opened to the outside with methods. The main purpose of encapsulation is to have full control over the data contained in the classes.

In encapsulation, variables of a class can be hidden from other classes and can only be accessed through the methods of its existing classes. For this reason, it is also known as data hiding.

public class Invoice implements Serializable {

private CurrentCard currentCard;
private String invoiceNo;
private BigDecimal netTotal;
private BigDecimal taxAmount;
private BigDecimal total;

public Invoice(CurrentCard currentCard, String invoiceNo) {
this.currentCard = currentCard;
this.invoiceNo = invoiceNo;
}

public void setInvoiceAmount(BigDecimal netTotal, BigDecimal taxAmount) {
this.taxAmount = netTotal.compareTo(BigDecimal.ZERO) > 0 ? netTotal.multiply(taxAmount).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP) : BigDecimal.valueOf(0);
this.total = netTotal.add(this.taxAmount);
}
}

Data Hiding/Data Encapsulation:

Encapsulation allows data to be hidden.

We use access modifiers to hide data (fields) and methods (methods).

Users use methods to access and update the data (fields) in the class. To do this; We mark our fields as private and write public methods.

ut as can be seen in the example above, what is meant here is to implement the business in a way that protects the behavior of the class, rather than writing the getter setter.

For example, so that we can update the amounts in our invoice class correctly, the “setInvoiceAmount” method takes the necessary information and ensures that the tax and total amount is calculated and determined correctly.

Abstraction

Abstraction is the process of hiding implementation details from the user, only functionality will be provided to the user.

In other words, it is to let the user know about what the object does rather than how it does it. In order to achieve this, the complex syntax and implementation in our class can be hidden and accessed with public methods.

The need for abstraction may vary depending on the point of view.

  • Hiding unnecessary details;
  • It can have more than one implementation;
  • Ensuring that when developing a complex system, it is developed in parts.
public abstract class Deployment {

public void runDeployment() {
this.cleanProject();
this.buildProject();
this.deployProject();
}

private void buildProject() {
System.out.println("mvn install");
}

private void cleanProject() {
System.out.println("mvn clean");
}

public abstract void deployProject();
}


public class SpringMvc extends Deployment {

@Override
public void deployProject() {
System.out.println("move jar to tomcat folder");
System.out.println("start tomcat");
}
}

public class SpringBoot extends Deployment {

@Override
public void deployProject() {
System.out.println("java -jar app.java");
}
}

Hiding unnecessary details;

In the above example, our goal is to deploy our spring application to our application server. In this process, mvn clean and install operations are a detail in the order of runDeployment operations. To reduce this complexity, we can create an abstruct class, hide these methods from the user, and reduce complexity.

It can have more than one implementation;

As in our example, there can be more than one way to deploy a spring application. There are differences in the process between being a spring boot application and being a spring mvc application. In order to prevent the user from being affected by these differences, an implementation can be made for the parts that differ only by pulling the abstruct into a class for the lower level parts and for the common parts. In this case, the only thing that interests the user is to call the runDeployment method.

Another example is List<String>. The user does not care whether the object is an ArrayList or a LinkedList. The relevant part is abstracted with interface. The user continues his operations using the List interface.

Spliting of a complex system:

Methods and Fields need to be split logically.

public class Vehicle {
BigDecimal price;
String brand;
String color;
int engineLiter;
int enginePower;
String wheelBrand;
BigDecimal wheelPrice;

void move() {

}

void turn() {

}

void startEngine() {

}
}

For the above example; Within the vehicle class, the engine and wheels are defined in one place. But; when new requrements comes for engines and wheels increase, the class will begin to become more complex.

So as to overcome this problem, we can use Abstruction an this help us reduce the confusion.

Abstraction has three advantages:

  1. Using abstraction, we can separate things that can be grouped into another type.
  2. Properties and methods that change frequently can be grouped into a separate type so that the parent type does not need to be changed. Open for extension, close for midification principle, one of the SOLID Principles, will also be provided with this solution.
  3. To reduce the dependencies of domain models on each other.

Tüm bunları düşünerek yukarda verdiğimiz Araç örneğini aşağıdaki gibi düzenleyebiliriz.

Considering all these, we can update the Vehicle example with above as follows.

public class Vehicle {
Engine engine;
Wheel wheel;
BigDecimal price;
String brand;
String color;

void move() {

}
}

public class Airplane extends Vehicle {
Integer numberOfPassinger;
Type type;

}

public class Engine
{
int engineLiter;
int enginePower;

void startEngine() {

}
}
public class Wheel
{
String wheelBrand;
BigDecimal wheelPrice;

void turn() {

}
}

As a Summary;

  • The abstraction is to find solutions to problems from a broad perspective with interface and abstruct classes, avoiding implementation as much as possible.
  • Abstraction can be used to organize our code.
  • Object Oriented Programming is based on complete abstraction.
  • Abstruction is a method of dividing a large problem into smaller parts and working in self-contained parts.

Encapsulation vs. Abstraction

The difference between the concepts of encapsulation and abstraction is that encapsulation is more about packaging the class (like how data should be accessed (getter/setter) and what data should be accessed (access specifiers)), whereas abstraction is more about what the class does.

Encapsulation is to hide unnecessary data in a class. But abstraction is the display of essential properties of an object.

Abstraction covers information hiding, encapsulation covers generalization.

Abstraction is a form of generalization: providing code development that applies to more than one specific case.

Abstraction is a method of hiding other information, where you focus only on details that are important to your purpose.

Inheritance is also an example of abstraction.

Inheritance

Inheritance is when one class has extensions of another class, it has also the behavior, methods and fields of super class.

Inheritance is type of a (is a) relationship. For example, Automobile is (is a) a Vehicle. Bus is a (is a) Vehicle.

public class Vehicle {
Engine engine;
Wheel wheel;
BigDecimal price;
String brand;
String color;

void move() {

}
}

public class Airplane extends Vehicle {
Integer numberOfPassinger;
Type type;
}

Types of Inheritance:

  1. Single Inheritance
  2. Multiple Inheritance
  3. Multi-Level Inheritance
  4. Hierarchical Inheritance
  5. Hybrid Inheritance
Type Of Inheritance

Note: Java, JavaScript etc. Most languages ​​do not support Multiple Inheritance. The Diamond Problem is encountered with the use of multiple inheritance. Without Multiple Inheritance, Hybrid Inheritance is not possible.

The Advantages of Inheritance is like that;

  1. Inheritance provides reusability. When a class inherits another class, it has access to all functions of the inherited class.
  2. When Existing code is reused, less development and reducing maintenance costs are also provided.
  3. Inheritance allows subclasses to follow a standard interface.
  4. Inheritance helps reduce code redundancy and supports code extensibility.

The Disadvantages of Inheritance is like that;

  1. Misuse of inheritance can lead to wrong solutions.
  2. If the data members in the base class are left unused; this can waste memory.
  3. Inheritance increases the link between the base class and the derived class. Any changes in the base class affects all subclasses.

Polymorphism

Polymorphism is the ability to assign a different meaning or usage to something in different contexts. It is a construct to allow an object to have more than one form.

There are 2 types of polymorphism implementations:

  1. Static Polimorfizm
  2. Dynamic Polimorfizm

Features of polymorphism mainly depend on programming languages.

Function overloading is possible in Java, C++, but not in JavaScript. Operator overloading is only possible in C++.

public class ExportUtils {

public void prepareReport() {
System.out.println("report is preparing");
}
}

public class PdfExport extends ExportUtils{
public void prepareReport() {
System.out.println("Pdf report is preparing");
}
}

public class WordExport extends ExportUtils{
public void prepareReport() {
System.out.println("Word report is preparing");
}
}

public class ExcelExport extends ExportUtils{
public void prepareReport() {
System.out.println("Excel report is preparing");
}
}

class Main {
public static void main(String[] args) {
ExportUtils pdfReport = new PdfExport(); // Create a pdf object
ExportUtils wordReport = new WordExport(); // Create a word object
ExportUtils excelExport = new ExcelExport(); // Create a excel object
pdfReport.prepareReport();
wordReport.prepareReport();
excelExport.prepareReport();
}
}

In the above example, we have a base class called ReportUtils. If we create an instance that refers to which class extends the ExportUtils class, the prepareReport method will run the report preparation method of the relevant class.

For Example:

ExportUtils wordReport = new WordExport();
wordReport.prepareReport();

The output of the above example will be printed as “Word report is preparing”.

In summary, polymorphism allows the behavior of a method to be changed during run time.

Senior Software Engineer