Most developers memorize:
"One interface, many forms."
Unfortunately, that definition is so abstract that it doesn't teach much.
Let's understand the actual problem polymorphism solves.
🤯 The Problem
Suppose you're building a payment system.
Without polymorphism:
class PaymentService {
processPayment(
type: string,
amount: number
) {
if (type === 'credit-card') {
// credit card logic
}
if (type === 'paypal') {
// paypal logic
}
if (type === 'upi') {
// upi logic
}
}
}
Works.
Then the business says:
Add Stripe
You modify:
if (type==='stripe') {}
Next month:
Add Apple Pay
Modify again.
Next:
Add Crypto
Modify again.
The class keeps growing.
This violates a key design principle:
Existing code should not need constant modification when new behavior is added.
✨ Polymorphism's Solution
Instead of asking:
What type are you?
ask:
Can you perform this action?
That's a huge mindset shift.
Example
Create a contract:
interface PaymentProvider {
process(amount:number):void;
}
Implementations:
class CreditCardPayment implements PaymentProvider {
process(amount: number) {
console.log('Credit Card');
}
}
class UpiPayment implements PaymentProvider {
process(amount: number) {
console.log('UPI');
}
}
Now:
function checkout(
provider: PaymentProvider,
amount: number
) {
provider.process(amount);
}
Usage:
checkout(new CreditCardPayment(),100);
checkout(new UpiPayment(),100);
checkout(new PaypalPayment(),100);
Same method call:
provider.process()
Different behavior.
This is polymorphism.
🧠 The Core Idea
Polymorphism means:
Treat different objects uniformly while allowing each object to behave differently.
You don't care:
Credit Card
UPI
PayPal
You only care:
Can you process a payment?
Real World Example
Think about a power socket.
You plug in:
- Laptop charger
- Phone charger
- Fan
- TV
The socket doesn't ask:
Are you a Samsung charger?
Are you a Dell charger?
It only expects:
Can you accept electricity?
Each device behaves differently after receiving power.
That is polymorphism.
Why Interfaces Matter
Consider:
interface UserRepository {
findById(id:string):Promise<User>;
}
Implementation 1:
class PostgresUserRepository implements UserRepository {}
Implementation 2:
class MongoUserRepository implements UserRepository {}
Implementation 3:
class InMemoryUserRepository implements UserRepository {}
UserService:
class UserService {
constructor(
privaterepo: UserRepository
) {}
}
Notice:
repo.findById()
works regardless of:
Postgres
Mongo
Memory
The service doesn't care.
That's polymorphism.
🔑 The Key Takeaway
Polymorphism is often described as:
"One interface, many forms."
A more practical way to think about it is:
Different objects can respond to the same request in their own way.
The caller doesn't need to know the implementation.
It only needs to know the capability the object provides.
This makes systems easier to extend without constantly modifying existing code.
⏭️ What's Next?
With this article, we've completed the four core pillars commonly associated with Object-Oriented Programming:
- Encapsulation
- Abstraction
- Inheritance
- Polymorphism
But understanding these concepts doesn't automatically lead to well-designed software.
Developers soon realized that even OOP applications could become difficult to maintain if responsibilities weren't clearly defined.
That realization gave rise to a new set of guidelines known as the SOLID Principles.
In the next article, we'll explore why SOLID was introduced and the problems it was designed to solve.
Top comments (0)