OOP FundamentalsEncapsulationHard⏱️ ~3 min

Trade-offs: When to Use Encapsulation

Decision Framework: Encapsulation is not free. It adds indirection and requires careful interface design. Understanding trade-offs helps make informed decisions.

When Encapsulation is Essential:
First, Complex Invariants: When multiple fields must stay synchronized (e.g., ParkingLot.capacity and occupiedCount), encapsulation prevents inconsistency.
Second, Validation Requirements: Business rules like "balance cannot be negative" or "age must be 0-120" require controlled access through methods.
Third, Future Flexibility: When internal representation might change (e.g., switching from array to HashMap for spots), encapsulation isolates clients from implementation.
Fourth, Security/Safety: Sensitive data like passwords, payment info, or permissions must be hidden and accessed through validated interfaces.
When Encapsulation is Overkill:
First, DTOs (Data Transfer Objects): Pure data containers like UserDTO or API request/response models have no invariants. Public fields or simple getters/setters suffice.
Second, Immutable Value Objects: Once created, fields never change. A Point(x, y) or Money(amount, currency) can expose fields as public final/readonly.
Third, Internal Helper Classes: Private nested classes used only within another class don't need encapsulation from themselves.
Fourth, Performance-Critical Code: In rare cases (game engines, numerical computing), direct field access avoids method call overhead. Profile first.
Encapsulated (Right)
class BankAccount {
  - balance: Money
  + withdraw(amt): Result
}
Has invariants (balance ≥ 0), validation needed
Public Fields (Right)
class Point {
  + readonly x: int
  + readonly y: int
}
Immutable, no invariants, simple data

Common Anti-Pattern: Anemic Getters/Setters

❌ False Encapsulation
class Account {
  - balance: Money
  + getBalance(): Money { return balance }
  + setBalance(b: Money) { balance = b }
}
Fields are private but setter allows any value. No validation. This is not true encapsulation—just indirection without protection.
✓ True Encapsulation
class Account {
  - balance: Money
  + deposit(amt: Money): void
  + withdraw(amt: Money): Result
  + getBalance(): Money
}
No setter. Behavior-focused methods that enforce rules. Balance can only change through validated operations.
Interview Tip: If asked "Should all fields be private with getters/setters?", answer "No". Explain DTOs vs domain objects. Show you understand the difference between mechanical encapsulation and protecting invariants.
💡 Key Takeaways
Encapsulation is essential when invariants must be protected
DTOs (Data Transfer Objects) don't need encapsulation
Getters/setters without validation are false encapsulation
Immutable value objects can safely expose fields
Trade verbosity for safety only when safety matters
📌 Examples
1BankAccount needs encapsulation, UserDTO does not
2Point as immutable value object with public fields
3ParkingSpot needs encapsulation to prevent double-booking
← Back to Encapsulation Overview