Object-Oriented Programming (OOP) is one of the most widely used programming paradigms, shaping how modern applications are designed and built.
At its core, OOP is based on four fundamental principles: Abstraction, Encapsulation, Inheritance, and Polymorphism.
Let’s break down each concept with explanations, examples, and best practices.
1 - Abstraction
Abstraction is the process of hiding complex implementation details while exposing only the essential features of an object. It allows developers to work with high-level concepts without worrying about the underlying implementation.
How It Works
Imagine a Car
class with a method called stop()
. Users of this class don’t need to know how the car stops—they just need to call stop()
, and the underlying implementation takes care of the details.
abstract class Car {
abstract void stop(); // Abstract method, no implementation
}
class Honda extends Car {
@Override
void stop() {
System.out.println("Honda slowing down and stopping.");
}
}
class Tesla extends Car {
@Override
void stop() {
System.out.println("Tesla applies brakes and stops.");
}
}
Here, Car
defines the stop()
method but doesn’t provide an implementation. Honda and Tesla provide their specific implementations, hiding the details from the users of these classes.
Why Abstraction Matters
Simplifies complex systems by exposing only necessary parts.
Improves code maintainability by separating the interface from implementation.
Enhances security by hiding implementation logic from unauthorized access.
2 - Encapsulation
Encapsulation is the concept of bundling data (fields) and methods that operate on the data into a single unit (class) while restricting direct access to the data.
How It Works
Encapsulation is achieved using access modifiers (private
, protected
, public
) to control access to variables and methods.
class BankAccount {
private double balance; // Private variable, cannot be accessed directly
public BankAccount(double initialBalance) {
this.balance = initialBalance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public double getBalance() {
return balance; // Provides controlled access to balance
}
}
Here balance
is private, so it cannot be accessed directly from outside. Also, getBalance()
is public, allowing controlled access to the balance.
Why Encapsulation Matters
Protects data integrity by preventing unauthorized modifications.
Reduces dependencies by keeping data and its operations in one place.
Enhances flexibility as changes to implementation don’t affect external code.
3 - Inheritance
Inheritance allows a class (child) to inherit attributes and methods from another class (parent). This promotes code reuse and hierarchical relationships between classes.
How It Works
Consider a Vehicle
class. Instead of rewriting common functionality for each type of vehicle, a Car
and Bike
can inherit from Vehicle
.
class Car {
String brand = "Generic Brand";
void honk() {
System.out.println("Beep! Beep!");
}
}
class Car extends Vehicle {
int doors = 4;
}
public class Main {
public static void main(String[] args) {
Car myCar = new Car();
System.out.println(myCar.brand); // Inherited from Vehicle
myCar.honk(); // Inherited method
System.out.println("Number of doors: " + myCar.doors);
}
}
Here, Car
inherits brand
and honk()
from Vehicle
, reusing existing logic.
Why Inheritance Matters
Reduces code duplication, making maintenance easier.
Creates hierarchical relationships (e.g.,
Animal → Mammal → Dog
).Improves extensibility, allowing new behaviors to be added to child classes.
4 - Polymorphism
Polymorphism allows a single method to behave differently based on the object it is called on. This means one function can be applied to multiple object types.
There are two types of polymorphism:
Compile-time
Run-time
How It Works
Here’s an example of polymorphism:
class MathOperations {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
MathOperations math = new MathOperations();
System.out.println(math.add(5, 10)); // Calls int version
System.out.println(math.add(5.5, 2.2)); // Calls double version
}
}
Here, the add()
method behaves differently based on the parameter type.
Why Polymorphism Matters
Enhances flexibility by allowing objects of different types to be treated uniformly.
Encourages code extensibility without modifying existing code.
Supports the Open-Closed Principle (OCP)—extend behavior without modifying existing logic.
So - have you used object-oriented programming? And are there any other concepts you find important?
Shoutout
Here are some interesting articles I’ve read recently:
Traditional Development’s Last Stand: The $20 Tools Making $20,000 Builds Obsolete by
How (not to) fail a coding interview by
Key concepts of System design 4 Redux: let's break it down by
Write Clean Commit Messages by
That’s it for today! ☀️
Enjoyed this issue of the newsletter?
Share with your friends and colleagues.
Uuuu another key concept 🙂 thanks for the mention bud 👍
Great article. I use JS :)