Classes as contracts: encapsulation, not secrecy
Private fields exist so public behavior can stay stable
Good classes hide their representation behind a narrow public interface of methods. This is not about secrecy; it is about stability. As long as the public methods keep their promises, you are free to rename, combine, or cache the fields behind them. Entire refactors live or die on whether external code depends on layout or on contract.
public final class Money {
private final long cents;
private final Currency currency;
public Money(long cents, Currency currency) {
if (currency == null) throw new IllegalArgumentException("currency required");
this.cents = cents;
this.currency = currency;
}
public Money add(Money other) {
if (!currency.equals(other.currency))
throw new IllegalStateException("cannot add different currencies");
return new Money(cents + other.cents, currency);
}
public long cents() { return cents; }
public Currency currency() { return currency; }
}Why constructors matter
Constructors are your one chance to establish invariants before anyone else uses the object. Validating once at construction saves dozens of defensive checks elsewhere. Immutable classes (final fields, no setters) push this principle to its natural conclusion: once built, they cannot be broken.
Takeaways
- Encapsulation buys you the freedom to change representation.
- Constructors establish invariants; private fields keep them.
- Prefer methods that express behavior over mechanical getter/setter pairs.
- Immutability eliminates whole categories of bugs — reach for it by default.
Enjoying This Lesson?
Your support helps create more comprehensive courses and lessons like this one. Help me build better learning experiences for everyone.
Support Awashyak