52

Encapsulate Collection


Goal

A class's internal collection is never returned directly; callers add or remove via methods on the class, and reads return a snapshot or iterator.

Before the refactoring
class Person {
  courses;
  getCourses() { return this.courses; }
}
After the refactoring
class Person {
  #courses = [];
  courses()       { return [...this.#courses]; }
  enroll(course)  { this.#courses.push(course); }
  drop(course)    { this.#courses = this.#courses.filter(c => c !== course); }
}
Savings

The owner can enforce invariants (uniqueness, ordering, max size); refactoring the collection's internal shape is local.

Note

Returning a shallow copy on every read can hide bugs where callers expected mutation to be reflected — be explicit about the contract.