The Four Pillars of OOP

Object-Oriented Programming (OOP) is built upon four fundamental principles, often referred to as the four pillars of OOP: Encapsulation, Inheritance, Polymorphism, and Abstraction. These principles help in organizing complex software programs, making them more manageable, scalable, and easier to understand. Let's delve into each of these pillars with real-world analogies and examples in Java.

Encapsulation:

Definition:

Encapsulation is the concept of wrapping data (attributes) and code (methods) together into a single unit, known as a class. It restricts direct access to some of the object's components, which is a means of preventing unintended interference and misuse of the data. Encapsulation is achieved using access modifiers such as private, protected, and public.

Real-World Analogy:

Consider a capsule in a medication bottle. The capsule contains the medicine (data) inside it. The capsule is sealed to prevent the medicine from being exposed or tampered with directly. You can only access the medicine by ingesting the capsule, not by opening it. Similarly, in programming, encapsulation protects the data inside an object and only allows it to be accessed through well-defined methods.

Example Code:

public class Person {
    // Private attributes
    private String name;
    private int age;
    
    // Public getter method for name
    public String getName() {
        return name;
    }
    
    // Public setter method for name
    public void setName(String name) {
        this.name = name;
    }
    
    // Public getter method for age
    public int getAge() {
        return age;
    }
    
    // Public setter method for age
    public void setAge(int age) {
        if (age > 0) { // Basic validation
            this.age = age;
        }
    }
}

// Main class to demonstrate encapsulation
public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("John Doe");
        person.setAge(30);
        
        System.out.println("Name: " + person.getName());
        System.out.println("Age: " + person.getAge());
    }
}

In this example:

  • The Person class has** private attributes name and age.**
  • Public getter and setter methods are provided to access and modify these attributes, ensuring that any necessary validation or processing can be done within these methods

Advantages of encapsulation

  • Classes are simpler to modify and maintain.
  • Which data member we wish to keep hidden or accessible can be specified.
  • We choose which variables are read-only and write-only (increases flexibility).

Inheritance:

Definition:

Inheritance is a mechanism in OOP that allows one class (the subclass) to inherit the properties and methods of another class (the superclass). This promotes code reuse and establishes a natural hierarchy between classes.

Real-World Analogy:

Consider a family tree. A child inherits traits and behaviors from their parents. Similarly, in programming, a subclass inherits attributes and methods from its superclass.

Example Code:

// Superclass
public class Animal {
    void eat() {
        System.out.println("This animal eats food.");
    }
}

// Subclass
public class Dog extends Animal {
    void bark() {
        System.out.println("The dog barks.");
    }
}

// Main class to demonstrate inheritance
public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        myDog.eat(); // Inherited method
        myDog.bark(); // Method from Dog class
    }
}

In this example:

  • The Animal class defines a method eat().
  • The Dog class extends the Animal class, inheriting the eat() method, and also has its own method bark().

Abstraction:

Definition:

Abstraction is the concept of hiding the complex implementation details and showing only the necessary features of an object. It helps in reducing programming complexity and effort. Abstraction can be achieved using abstract classes and interfaces.

Real-World Analogy:

Consider driving a car. When you drive, you only need to know how to use the steering wheel, pedals, and other controls. You do not need to understand the intricate workings of the engine or the electronic systems. Similarly, abstraction in programming hides complex details and exposes only the essential features.

Example Code:

// Abstract class
abstract class Shape {
    abstract void draw();
}

// Concrete class extending abstract class
public class Circle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a circle");
    }
}

// Main class to demonstrate abstraction
public class Main {
    public static void main(String[] args) {
        Shape myShape = new Circle();
        myShape.draw(); // Calls the draw method of Circle
    }
}

In this example:

  • The Shape class is abstract, meaning it cannot be instantiated directly and must be subclassed.
  • The Circle class provides a concrete implementation of the draw method.

Polymorphism

Definition:

Polymorphism means "many shapes" and allows one interface to be used for a general class of actions. The specific action is determined by the exact nature of the situation. Polymorphism is often achieved through method overloading and method overriding.

Real-World Analogy:

Consider a person who can be a teacher, a parent, or a friend. Depending on the context, the person will behave differently. In programming, polymorphism allows objects to be treated as instances of their parent class rather than their actual class, while still performing specific behaviors.

Example Code:

// Method Overloading (Compile-time Polymorphism)
public class MathOperations {
    int add(int a, int b) {
        return a + b;
    }
    
    double add(double a, double b) {
        return a + b;
    }
}

// Method Overriding (Runtime Polymorphism)
public class Animal {
    void sound() {
        System.out.println("Animal makes a sound");
    }
}

public class Cat extends Animal {
    @Override
    void sound() {
        System.out.println("Cat meows");
    }
}

// Main class to demonstrate polymorphism
public class Main {
    public static void main(String[] args) {
        // Compile-time Polymorphism
        MathOperations math = new MathOperations();
        System.out.println(math.add(2, 3)); // Calls int version
        System.out.println(math.add(2.5, 3.5)); // Calls double version
        
        // Runtime Polymorphism
        Animal myAnimal = new Cat();
        myAnimal.sound(); // Calls the Cat's sound method
    }
}

In this example:

  • Method overloading is demonstrated with the add methods in the MathOperations class.
  • Method overriding is demonstrated with the sound method in the Animal and Cat classes.

Now with this all the 4 pillars and there indepth explanation is over. But there are some important concepts which you should be aware of for the interviews related to these:

  1. Diamond Problem in Inheritance in Java.
  2. Difference between Abstraction and Encapsulation , since both are esentially hiding the internal working.
  3. Dynamic Polymorphism vs Static Polymorphism.

To be continued...

Link to the next article : https://leetcode.com/discuss/interview-question/object-oriented-design/5345963/OOPS-REVISION-3-or-JAVA

Comments (2)