Command Palette

Search for a command to run...

PHASE 1Beginner ~7 min· topic 1 of 5

Topic 1.1

OOP

In one line

Four pillars (encapsulation, inheritance, polymorphism, abstraction) plus the relationship vocabulary (composition, aggregation, association, dependency) that LLD answers are built from.

0/5 · 0%

Think of it like this

A TV remote. You press 'volume up' without knowing about the circuits inside (encapsulation + abstraction). Every brand's remote has a volume button that works differently inside (polymorphism).

Key ideas

  1. 01

    Encapsulation: keep state private, expose behavior — a class is a contract, not a data bag.

  2. 02

    Inheritance ('is-a'): reuse via hierarchy; brittle, violates encapsulation of parent internals.

  3. 03

    Polymorphism: one interface, many implementations — the root of strategy and dependency inversion.

  4. 04

    Abstraction: hide complexity behind a stable interface; change the inside without changing callers.

  5. 05

    Composition ('has-a'): build objects from other objects; the recommended replacement for deep inheritance.

  6. 06

    Aggregation: 'has-a' where the part can outlive the whole (Team has Players; remove team, players remain).

  7. 07

    Association: any structural relationship, usually a directional reference (Doctor ↔ Patient).

  8. 08

    Dependency: a class uses another as a parameter or local (weakest, most common link).

  9. 09

    Pattern mantra: 'Prefer composition over inheritance' — inheritance is not banned, just expensive to change.

Java / Spring map

  • →

    Spring's @Component model is composition-driven: services are assembled at runtime.

  • →

    Java 17 sealed interfaces / records make OO modeling small and precise.

Code & diagrams

CompositionInheritance.javajava

Why composition beats inheritance for change. A Decorator-style stack can be assembled at runtime.

// PROBLEM: capabilities × kinds explode an inheritance tree.
// {Duck, Penguin, Robot} × {can fly?, can swim?} → FlyingSwimmingDuck,
// NonFlyingSwimmingPenguin, ... one subclass per combination (up to 3×4 = 12),
// and "fly" logic is copy-pasted across unrelated branches (Bird, Plane).
class Bird extends Animal { void fly() {} }
class Plane extends Vehicle { void fly() {} }   // same behaviour, duplicated

// COMPOSITION: behaviours are objects injected at runtime.
interface FlyBehaviour { void fly(); }
class JetFly implements FlyBehaviour {
  public void fly() { System.out.println("fast"); }
}
class NoFly implements FlyBehaviour {
  public void fly() { /* nothing */ }
}

class Character {
  private final FlyBehaviour fly;          // injected → composition
  Character(FlyBehaviour fly) { this.fly = fly; }
  void move() { fly.fly(); }
}

// Now a bird that cannot fly is just: new Character(new NoFly());
// Adding "glide" never touches Character.

Explain without notes

01

When is inheritance genuinely the right tool?

02

What happens to the class hierarchy when requirement 'birds swim' appears?

Practice

01

Model a Zoo with mammals/birds and feeding behaviour — use composition, then refactor to inheritance and feel the difference.

Trade-offs

  • ↔

    Composition creates many tiny classes; shallow hierarchies are simpler to read but harder to extend.

Completion checklist

  • I can distinguish aggregation vs composition with a life-cycle example.

  • I can justify composition-over-inheritance in one minute.

Back to phase