โ† Back to OOP Concepts
๐Ÿ”€
Pillars

Polymorphism

Allows objects of different types to be treated through a common interface, with each type providing its own behavior for the same call.

The Problem

Without polymorphism, code must use type-checks and branching (if/else or switch on type) to handle different object types โ€” logic that grows and becomes error-prone every time a new type is added.

How It Works

  • โ€บThe same method call produces different behavior depending on the runtime type of the object
  • โ€บAchieved via method overriding (subtype polymorphism) or interfaces/protocols
  • โ€บEliminates type-checking conditionals โ€” the right implementation is dispatched automatically
  • โ€บEnables writing generic code that works with any conforming type

When to Use

โœ“Processing heterogeneous collections uniformly (e.g., an array of Shape)
โœ“Plugin or strategy systems where behavior varies by type
โœ“Replacing switch-on-type logic with dynamic dispatch

Real-World Examples

๐ŸŽ
iOS

draw() called on any UIView subclass renders that subclass's own appearance

๐Ÿค–
Android

onClick() behaves differently depending on the View subclass's listener

๐ŸŒ
Web

toString() overridden per class to produce custom string representations

Code Examples

Swift
protocol Shape {
    func area() -> Double
}

struct Circle: Shape {
    let radius: Double
    func area() -> Double { .pi * radius * radius }
}

struct Rectangle: Shape {
    let width: Double
    let height: Double
    func area() -> Double { width * height }
}

let shapes: [Shape] = [Circle(radius: 2), Rectangle(width: 3, height: 4)]
for shape in shapes {
    print("Area: \(shape.area())")
}