โ Back to OOP Concepts
๐
Pillars
Encapsulation
Bundles data and the methods that operate on that data within a single unit, restricting direct access to an object's internal state.
The Problem
Without encapsulation, external code can directly read and mutate an object's fields, leading to invalid states, broken invariants, and tight coupling between callers and internal implementation details.
How It Works
- โบFields are kept private; access is mediated through public methods or computed properties
- โบInternal representation can change without breaking external code
- โบValidation and invariant-checking logic lives in one place โ setters enforce the rules
- โบReduces coupling: callers depend on behavior, not on internal structure
When to Use
โProtecting invariants (e.g., a balance can never go negative)
โHiding implementation details that may change later
โExposing a controlled, minimal API surface for a class
Real-World Examples
๐
iOS
private(set) properties and computed properties with custom setters
๐ค
Android
Kotlin private fields exposed via custom getters/setters or data class validation
๐
Web
JavaScript private class fields (#balance) accessible only through methods
Code Examples
Swift
class BankAccount {
private var balance: Double = 0
init(initialBalance: Double) {
balance = initialBalance
}
func deposit(_ amount: Double) {
guard amount > 0 else { return }
balance += amount
}
func withdraw(_ amount: Double) -> Bool {
guard amount > 0, amount <= balance else { return false }
balance -= amount
return true
}
var currentBalance: Double { balance }
}
let account = BankAccount(initialBalance: 100)
account.deposit(50)
print(account.currentBalance) // 150