A Dive into OOP Concepts 😺 with Examples

Sanjay SSanjay S
6 min read

Photo by orbtal media on Unsplash

You might have already using OOP concepts without knowing it! So here I am, to share my learnings on this topic OOP.

Exactly an year ago, I published a blog “A Look into SOLID principles with Examples. It reached many people, so I am going to follow the same format.

In some example I would have added cross-reference to the SOLID Principles blog.

This blog assumes that you have a basic understanding of Classes and Objects in at-least one language. But but I’ll use Java as an example here for every concept.

As you might know we have four pillars for OOP.

  • Abstraction

  • Encapsulation

  • Inheritance

  • Polymorphism

These pillars will help use to write maintainable code with less hassle. But as like other principles overusing may affect your code in the worst way possible.

We will go into the pillars one by one and learn the concept with an example.

Important thing to remember: Some concepts are interlinked to each other, so you cannot learn without overlapping with others. Some are totally different from others.

Abstraction

Abstraction hides information that is not relevant to the context or rather shows only relevant information and simplifies

In Simple words, Abstraction means hide away the complexity and show only required things.

In even Simple words, Hiding for Simplicity.
Did you noticed, I just explained Abstraction by using Abstraction.

Example:

interface Operator {
  void switchOn();
  void switchOff();
}

class PackagingOperator implements Operator {
  private boolean onStatus;

  public void switchOn() {
    onStatus = true;
    sendNotification();
  }

  public void switchOff() {
    onStatus = false;
    sendNotification();
  }

  private void sendNotification() {
    // Send Mail about the status
  }
}

In this example, Operator interface only says about two functions switchOn & switchOff . It doesn’t have any other functions related to how switching on, or switching off.

This overlaps with Dependency Inversion Principle (DIP) from SOLID principles. As using only an Interface or Abstract class (in align with DIP principle) helps to achieve Abstraction.

Key Points:

  • Hides for Simplicity

  • Focuses on what an object does, not how it does it.

  • Mostly uses abstract class, interface to define methods.

  • It doesn’t have the full implementation, so we need some concrete classes to provide logic.

  • It hides complex behavior behind a simplified interface.

Encapsulation

Wrapping data and methods within classes in combination with implementation hiding (through access control) is often called encapsulation.

Here also we will hide things but for different purpose, Safety and Security.

We will hide the data and methods using access modifiers (private, public).
Let’s take the previous example,

class PackagingOperator implements Operator {
  private boolean onStatus;

  public void switchOn() {
    onStatus = true;
    sendNotification();
  }

  public void switchOff() {
    onStatus = false;
    sendNotification();
  }

  private void sendNotification() {
    // Send Mail about the status
  }
}

Here the onStatus, sendNotification() is hidden using private.

Another simple example would be an POJO class, User.

class User {
  private String name;
  private Long dateOfBirth; // Timestamp in seconds
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public int getAge() {
    int age = ... - dateOfBirth;// Do some calculation with dateOfBirth value

    return age;
  }
  public void setAge(int age) {
    Long dateOfBirth = ... - age; // Do some calculation with age value
    this.dateOfBirth = dateOfBirth;
  }
}

Here I restricted the direct access to name by defining public getters and setters. That looks like a unnecessary methods until you analyze what I did in the case of age.

There is no agevariable, instead I am calculating the age from dateOfBirth long variable. (Because that’s how real-world works, you won’t store age, you store DOB to calculate Age anytime). Even I restricted direct access to dateOfBirth.

Key Points:

  • Hides for Security

  • Hiding the state or internal representation of an object for safety

  • Uses access modifiers to restrict direct access to fields and expose behavior through controlled methods.

Inheritance

Mechanism by which one class acquires the properties and behaviors of the parent class

You can think of it like extending a class but without modifying it. (Seems like its supporting the Liskov Substitution Principle — LSP).

Example:

abstract class Vehicle {
  String brand;

  Vehicle(String brand) {
      this.brand = brand;
  }

  void move() {
      System.out.println(brand + " is moving.");
  }

  // Abstract method: must be implemented by subclasses
  abstract void startEngine();
}

class Car extends Vehicle {
  int wheels;

  Car(String brand, int wheels) {
      super(brand);
      this.wheels = wheels;
  }

  @Override
  void startEngine() {
      System.out.println(brand + " car engine started with key.");
  }

  void fuelType() {
      System.out.println(brand + " uses petrol or diesel.");
  }
}
class ElectricCar extends Car {
  int batteryCapacity;

  ElectricCar(String brand, int wheels, int batteryCapacity) {
      super(brand, wheels);
      this.batteryCapacity = batteryCapacity;
  }

  // Override startEngine to reflect electric behavior
  @Override
  void startEngine() {
      System.out.println(brand + " electric car started silently.");
  }

  void chargeBattery() {
      System.out.println(brand + " is charging: " + batteryCapacity + " kWh.");
  }
}

Here Vehicle is an Abstract concept (Abstraction), Car inherits the move method from Vehicle. Electric Car inherits all the methods from Car.

This is a “Is-A” relation. Eg: Electric Car is a Car, Car is a Vehicle.

Key Points:

  • Is-A relation

  • Mechanism to acquire all the properties from one class to another

Polymorphism

ability of a function to behave differently based on the context

Poly — Many, Morph — Forms = Many Forms

This can be classified into two:

  • Compile time (Static binding)

  • Run time (Dynamic binding)

This overlaps with Abstraction and Inheritance, Let’s see.

Compile Time Polymorphism:

When you declare functions with the same name in the same class (or Parent class), based on the input type the function that is called differs.

Example:

class PaymentProcessor {
  public void pay(double amount) {
      System.out.println("Paid ₹" + amount + " using default method.");
  }

  public void pay(double amount, String method) {
      System.out.println("Paid ₹" + amount + " using " + method + ".");
  }

  public void pay(double amount, String method, String currency) {
      System.out.println("Paid " + currency + amount + " using " + method + ".");
  }
}

Here if you call paywith single parameter, the first function is called.
If you call pay with two parameters (types also should match or else compile error), second function is called. If you call pay with three parameters, last method is called.

This is also called Method overloading.

Run Time Polymorphism:

When you declare the same method as in parent class, based on the instance object the function is called.

Example:

class Animal {
  void makeSound() {
      System.out.println("Animal makes a sound");
  }
}

class Dog extends Animal {
  @Override
  void makeSound() {
      System.out.println("Dog barks");
  }
}

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

// Main function
Animal animal = new Animal();
animal.makeSound(); // Animal makes a sound
animal = new Dog();
animal.makeSound(); // Dog barks
animal = new Cat();
animal.makeSound(); // Cate meows

Here Dog and Cat overrides the method makeSound but still the method is called based on the instance (Dogor Cat).

This is called Method Overriding.

Key Points:

  • the ability of a function to behave differently based on the context

  • Compile Time Polymorphism — Method Overloading

  • Run time Polymorphism — Method Overriding

Conclusion

Most of the principles overlaps, that’s because principles are to be supported by each other, so you apply one correctly, you are indirectly applying others.

If you have come this far, Thank you for reading this article.

Connect with me:

My Personal Portfolio: https://sanjaydev.tech

Sources:

0
Subscribe to my newsletter

Read articles from Sanjay S directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sanjay S
Sanjay S

I am currently working as a Software Developer @Esko. I have been learning Android from past 3 years from my College doing trial and errors. I can say I have more experience in knowing errors than code. I have also developed web applications in React.