โ† 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