DEV Community

Cover image for Polymorphism in OOP: One Interface, Multiple Implementations
Ashay Tiwari
Ashay Tiwari

Posted on

Polymorphism in OOP: One Interface, Multiple Implementations

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
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Works.

Then the business says:

Add Stripe
Enter fullscreen mode Exit fullscreen mode

You modify:

if (type==='stripe') {}
Enter fullscreen mode Exit fullscreen mode

Next month:

Add Apple Pay
Enter fullscreen mode Exit fullscreen mode

Modify again.

Next:

Add Crypto
Enter fullscreen mode Exit fullscreen mode

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?
Enter fullscreen mode Exit fullscreen mode

ask:

Can you perform this action?
Enter fullscreen mode Exit fullscreen mode

That's a huge mindset shift.

Example

Create a contract:

interface PaymentProvider {
  process(amount:number):void;
}
Enter fullscreen mode Exit fullscreen mode

Implementations:

class CreditCardPayment implements PaymentProvider {

  process(amount: number) {
    console.log('Credit Card');
  }
}
Enter fullscreen mode Exit fullscreen mode
class UpiPayment implements PaymentProvider {

  process(amount: number) {
    console.log('UPI');
  }
}
Enter fullscreen mode Exit fullscreen mode

Now:

function checkout(
  provider: PaymentProvider,
  amount: number
) {
  provider.process(amount);
}
Enter fullscreen mode Exit fullscreen mode

Usage:

checkout(new CreditCardPayment(),100);

checkout(new UpiPayment(),100);

checkout(new PaypalPayment(),100);
Enter fullscreen mode Exit fullscreen mode

Same method call:

provider.process()
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

You only care:

Can you process a payment?
Enter fullscreen mode Exit fullscreen mode

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?
Enter fullscreen mode Exit fullscreen mode

It only expects:

Can you accept electricity?
Enter fullscreen mode Exit fullscreen mode

Each device behaves differently after receiving power.

That is polymorphism.


Why Interfaces Matter

Consider:

interface UserRepository {
  findById(id:string):Promise<User>;
}
Enter fullscreen mode Exit fullscreen mode

Implementation 1:

class PostgresUserRepository implements UserRepository {}
Enter fullscreen mode Exit fullscreen mode

Implementation 2:

class MongoUserRepository implements UserRepository {}
Enter fullscreen mode Exit fullscreen mode

Implementation 3:

class InMemoryUserRepository implements UserRepository {}
Enter fullscreen mode Exit fullscreen mode

UserService:

class UserService {
  constructor(
   privaterepo: UserRepository
  ) {}
}
Enter fullscreen mode Exit fullscreen mode

Notice:

repo.findById()
Enter fullscreen mode Exit fullscreen mode

works regardless of:

Postgres
Mongo
Memory
Enter fullscreen mode Exit fullscreen mode

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)