Encapsulate Collection

Referenced by patterns
Compare
Symptom
Human

A class exposes a collection field directly (getter returning the internal array, public field, etc.) — callers can mutate the collection from outside.

Agent

A class returns its internal collection directly; the agent reading any consumer cannot tell whether mutations will affect the owner without checking every consumer.

Goal
Human

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.

Agent

The owner exposes mutation methods (add, remove, replace); reads return snapshots or iterators; the agent reasons about collection invariants on the owner alone.

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); }
}
Example source: Illustrative example written for this site, not a quotation from any source.
Pressure
Human

Invariants on the collection (size, uniqueness, ordering) can't be enforced; bugs hide where one consumer mutates the collection in a way another assumed wouldn't happen.

Agent

Any consumer can mutate the collection in ways another consumer didn't expect; the agent verifying behavior must trace every read+mutation site to confirm invariants.

Tradeoff
Human

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

Agent

Returning a shallow copy on every read can hide bugs where callers expected mutation-back; the agent must be explicit about the read contract or risk silent no-ops.

Relief
Human

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

Agent

The owner enforces invariants in one place; the agent refactoring the collection's internal shape stays local to the owner.

Trap
Human

Returning a shallow copy on every read without telling callers — they expect mutations to be reflected, get silent no-ops, and bugs appear in unexpected places.

Agent

Returning copies silently changes the contract callers depended on — the agent shipping the encapsulation must verify every reader doesn't rely on mutate-the-returned-collection semantics.