Encapsulation is the practice of bundling an object's data together with the methods that operate on it, and restricting direct access to that data from outside the object. The object exposes a controlled, public interface (its methods) while hiding its internal state and implementation details.
Think of a car's dashboard: pressing the accelerator pedal makes the car go faster, but you don't need to know (or be able to directly manipulate) the fuel injection timing, spark plug voltage, or engine RPM calculations happening underneath. The car 'encapsulates' that complexity behind a simple pedal interface.
class BankAccount {
private balance = 0
function deposit(amount) {
if amount <= 0: throw Error("Amount must be positive")
this.balance += amount
}
function withdraw(amount) {
if amount > this.balance: throw Error("Insufficient funds")
this.balance -= amount
}
function getBalance() {
return this.balance
}
}
External code cannot do account.balance = -500 directly — it must call deposit() or withdraw(), both of which enforce the account's business rules. This guarantees the balance can never become invalid, no matter how many different parts of a large codebase interact with the account.
Why encapsulation matters:
- Protects data integrity — invalid states become impossible, not just discouraged
- Reduces coupling — other code depends only on the public interface, not internal implementation, so the internals can change freely without breaking anything else
- Simplifies usage — callers only need to understand a small public API, not the whole internal complexity
- Enables validation — every mutation goes through code that can enforce rules