liveBook · Manning

Encapsulation

As explained in The Art of Code

Encapsulation is a design principle that restricts direct access to internal state and exposes controlled operations for maintaining object invariants.

Encapsulation restricts direct access to internal state and exposes controlled operations that preserve consistency. It is useful when a type has real rules to protect, but it is not free: routine data objects can acquire constructors, accessors, setters, equality code, string representations, and builders until the supporting machinery obscures the data’s meaning. section 4.1.2 section 4.4

Use encapsulation to separate a stable, high-level action from details that may vary. A report-generation operation should tell the story—generate this report—without embedding the format-specific implementation. A shared interface can encapsulate interchangeable PDF, CSV, Excel, or later HTML behaviors, leaving orchestration small and allowing formats to grow independently. section 3.2.4

Hide report formats behind an operation

A conditional dispatcher couples report generation to every known format: each new format changes the method. Replacing format checks with a ReportGenerator interface moves generation details into implementations. The caller supplies a generator, and orchestration becomes report.generate(data). This is encapsulation of interchangeable behavior behind a common operation, aligned with the Strategy Pattern. section 3.2.4

Listing 3.4 Generating sales reports
public void generateReport(ReportFormat format, List<Data> data) {
  if (ReportFormat.PDF.equals(format)) {
    generatePdf(data);
    return;
  } else if (ReportFormat.CSV.equals(format)) {
    generateCsv(data);
    return;
  } else if (ReportFormat.EXCEL.equals(format)) {
    generateExcel(data);
    return;  }
  throw new UnsupportedOperationException(String.valueOf(format));  
}

The conditional version makes the coupling visible: format selection and format-specific generation occupy the same method, so extending formats expands its control flow. section 3.2.4

For plain data carriers, distinguish protection from ceremony. A Person with many optional constructor parameters can become unreadable and error prone; constructor overloads multiply quickly, while a builder makes selected fields explicit. Yet even a fully encapsulated two-field DTO may contain more boilerplate than domain meaning. Prefer small, precisely named data carriers and use validation where it has value rather than adding layers by habit. section 4.1.2 section 4.4

Choose the boundary by asking what must remain stable:

  • Hide implementation variation when clients need one enduring action but implementations can change independently. section 3.2.4
  • Protect mutable state when uncontrolled changes could create inconsistency; account for the defensive and accessor code this requires. section 4.1.2
  • Keep simple data visible and meaningful when boilerplate would outweigh its purpose; use concise immutable carriers where available. section 4.4

How The Art of Code covers it

How deep it goes
Examines consistency protection and boilerplate costs, then contrasts behavior encapsulation with concise data carriers.
Examples
Uses PDF, CSV, and Excel report generators plus Person constructors, a builder, and a boilerplate DTO.
What it assumes
Assumes familiarity with object-oriented classes, constructors, methods, and mutable state.
What you can do after
Evaluate/understand when controlled operations protect meaningful rules and when simpler data modeling better preserves intent.
How it connects
Connects encapsulation with Strategy Pattern, polymorphism, builders, mutable data, records, and pattern matching.

Also explained in

Compare how 14 books explain encapsulation →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Art of Code. The section links point to the parts of the book it draws on.