The OOP Model โ Objects All the Way Down
Lesson 6: The OOP Model โ Objects All the Way Down
OOP's core promise: bundle state and behavior together into objects, and hide the internals behind a clean interface. Your program is a network of objects that collaborate by sending each other messages (method calls). Where FP says "data flows through functions," OOP says "objects with state and behavior talk to each other."
The Four Pillars
- Encapsulation โ an object owns its data; outsiders can only go through its methods. The object's internal representation can change without breaking its users.
- Abstraction โ expose what an object can do, hide how it does it.
- Inheritance โ classes reuse behavior from parent classes (and interfaces define contracts).
- Polymorphism โ different objects respond to the same message in their own way.
class BankAccount {
#balance = 0; // private field โ encapsulated
constructor(owner) {
this.owner = owner;
}
deposit(amount) {
if (amount <= 0) throw new Error("Invalid amount");
this.#balance += amount;
}
withdraw(amount) {
if (amount > this.#balance) throw new Error("Insufficient funds");
this.#balance -= amount;
}
get balance() {
return this.#balance;
}
}
const account = new BankAccount("Zonderkep");
account.deposit(100);
account.withdraw(30);
console.log(account.balance); // 70
Notice the guarantees: the balance can never go negative, only deposit/withdraw touch it, and outsiders can't corrupt the state โ they can only send messages. The class is the guardian of its own invariants.
Inheritance & Polymorphism
Inheritance lets one class reuse and extend another. Polymorphism is the payoff: code written against a base type works with any subclass, because each object answers the same message in its own way.
class Shape {
area() { return 0; }
}
class Circle extends Shape {
constructor(r) { super(); this.r = r; }
area() { return Math.PI * this.r * this.r; }
}
class Rectangle extends Shape {
constructor(w, h) { super(); this.w = w; this.h = h; }
area() { return this.w * this.h; }
}
const shapes = [new Circle(2), new Rectangle(3, 4)];
const total = shapes.reduce((sum, s) => sum + s.area(), 0);
// โ 12.57 + 12 = 24.57 โ same message "area()", different answers
This is what enables plugin architectures, dependency injection, and frameworks: they define interfaces, and your objects plug in by implementing them. The framework calls you; you don't call it.
Where OOP Shines
- Domain entities with identity and lifecycle: Customer, Order, Invoice โ things that exist, persist, and change over time.
- UI widgets and frameworks: buttons, windows, components โ stateful things that react to events.
- Plugin/extension systems: polymorphism gives you "drop in a new implementation" for free.
- Encapsulating complex mutable subsystems: a database connection pool, a game engine, a device driver โ hide the mess behind a small API.
- Ecosystem momentum: if your stack is Java/Spring or C#/.NET, OOP is the house style and its tooling assumes it.
๐ง Knowledge Check
1. Encapsulation means:
2. Polymorphism lets you:
3. What is the "fragile base class" problem?