# Polymorphism

> Different objects, same call — code written against a shared interface works with any implementation without knowing the specific type.

- **Category**: Oop Concepts
- **Subcategory**: relationships
- **Canonical URL**: https://designpattern.fyi/oop-concepts/polymorphism/

---

## Description
**Intent**: Write code once that works with any implementation of an interface — add new types without touching the calling code.

**Context**: You have a list of Shape objects — Rectangle, Circle, Triangle. You want to call area() on each without type-checking which kind it is. Without polymorphism, that's an if-else chain that grows with every new shape you add.

**Solution**: Define a shared interface or base class with the methods that must be implemented. Concrete classes provide their own implementations. Calling code is written against the interface only — it works with any concrete type that honors the contract, including ones added later.



## Use Cases
Any collection of objects that differ in behavior but share a common operation (shape.area(), payment.process(), notifier.send()). Building plugin or extension systems where new types are added without modifying core logic. Replacing type-switch or if-else-instanceof chains that grow with every new type.



## Implementation Example

```javascript
class Shape {
  area() {
    throw new Error('Must implement area method');
  }
}

class Rectangle extends Shape {
  constructor(width, height) {
    super();
    this.width = width;
    this.height = height;
  }
  area() {
    return this.width * this.height;
  }
}

class Circle extends Shape {
  constructor(radius) {
    super();
    this.radius = radius;
  }
  area() {
    return Math.PI * this.radius ** 2;
  }
}

const shapes = [new Rectangle(5, 3), new Circle(2)];
shapes.forEach(shape => console.log(shape.area()));
```



## Trade-offs


### Advantages

- Calling code is isolated from concrete types — add new implementations without changing callers

- Replaces brittle if-else-instanceof chains with extensible, open-closed design

- Behavior is determined at runtime by the actual object — flexible and late-bound




### Considerations & Drawbacks

- Actual behavior can be less obvious — you need to know the runtime type to understand what runs

- Complex class hierarchies make the polymorphic chain harder to follow

- Runtime dispatch has a small performance cost in hot paths







