4 Pillars Of Object-Oriented Programming (Made Easy)
Published: 2021-07-01 20:47:40

Hey guys! OOP really isn't scary at all. In this article, I'll explain the 4 pillars of object-oriented programming or OOP without lengthy explanation. The code snippets will be in Java (don't worry C# fans, they're both the same language pretty much).

###[1] Encapsulation
A lot of people mix up encapsulation and abstraction, but these two are different. Encapsulation is the method of encapsulating data and methods (that use that data) in a single unit. 
```java
public class Whatever {
    public int salary = 0;
    
    public int getSalary() {
        return salary;
    }
}
```
This is encapsulation because we're grouping together data (salary) as well as method that use that data (getSalary()) inside a class.

###[2] Abstraction
To understand this, you need to understand the English word "abstraction", and that pretty much means hiding or something similar. Therefore, in OOP, abstraction means hiding the complexity and exposing only what's necessary. Now, I'll use the previous code snippet and add abstraction to it.
```java
public class Whatever {
    private int salary = 0;
    
    public int getSalary() {
        return salary;
    }
}
```
Here, the difference is that salary field is made private, which means no objects can change the data. However, for whatever reason we want this salary to be read by any objects so the getSalary() method remains public and can be called by any objects. Basically, we're hiding the field because we don't want any objects to modify this salary in this case.

###[3] Inheritance
If a class has some implementation which is used by another class too, we've got some duplication over here. A quick fix to avoid this is to send the code up to a parent class and then both these classes will extend to the parent class and get the same implementation (except that there's no code repetition). 

First let's take a look at an implementation without inheritance:
```java
public class Student {
    public void login() {
        // ...
    }
    
    public void getMarks() {
        // ...
    }
}

public class Teacher {
    public void login() {
        // ...
    }
    
    public void setMarks(int marks) {
        // ...
    }
}
```
Here, the problem is we've repeated some common codes between these two classes. It would be better if the common codes are present in a single place and these classes "connect" to the single place and yes it's possible with inheritance. Here's how inheritance can make the codebase simpler:
```java
public class User {
    public void login() {
        // ...
    }
}

public class Student extends User {
    public void getMarks() {
        // ...
    }
}

public class Teacher extends User {
    public void setMarks(int marks) {
        // ...
    }
}
```
This is much more cleaner. A student can getMarks(), while a teacher can setMarks(), and both of them can login(). No code repetition. With that said, inheritance (especially more than 1 level of inheritance) is bad as it sort of "disconnects" the mind of developers and might confuse them. Basically, the code will be harder to grasp. Use inheritance up to 1 or 2 levels only and when it wouldn't confuse anyone. 

###[4] Polymorphism
Poly means many, morph means forms, and -ism is probably an English suffix to make words sound good. Polymorphism means that an object can take many forms. Consider the following code:
```java
public class User {
    // ...
}

public class Student extends User {
    public void saySomething() {
        System.out.println("I am a student");   
    }
} 

public class Teacher extends User {
    public void saySomething() {
        System.out.println("I am a student");   
    }
}

public class LabAssistant extends User {
    public void saySomething() {
        System.out.println("I am a lab assistant");   
    }
}
```
Now, I'll create three distinct objects (which all have the saySomething() method with own implementation) and store them in an array:
```java
public class Main {
    public static void main(String[] args) {
        User[] objects = { new Student(), new Teacher(), new LabAssistant() };
        
        for (var obj : objects)
            obj.saySomething();
    }
}
```
In this case, we're looping over an array of different objects and then invoking saySomething() method. For element one, the object will invoke saySomething() in Student class, for element two, the object will invoke saySomething() in Teacher class, and so on. See? This object just took many forms, a.k.a polymorphism.