Cover of Refactoring by Martin Fowler, Kent Beck - Business and Economics Book

From "Refactoring"

Author: Martin Fowler, Kent Beck
Publisher: Addison-Wesley Professional
Year: 1999
Category: Computers

🎧 Free Preview Complete

You've listened to your free 10-minute preview.
Sign up free to continue listening to the full summary.

🎧 Listen to Summary

Free 10-min Preview
0:00
Speed:
10:00 free remaining
Chapter 7: Encapsulation
Key Insight 2 from this chapter

Encapsulate Collection

Key Insight

Encapsulating mutable data, especially collections, is crucial for maintaining control over how data structures are modified, thereby simplifying future changes. A common pitfall arises when a getter method for a collection returns the collection itself, allowing external code to alter its membership directly without the owning class's intervention. To prevent this, the owning class should provide explicit collection modifier methods, such as 'add' and 'remove', ensuring all changes flow through a controlled interface. While relying on team habits to avoid direct modification is possible, a more robust approach involves ensuring the getter for the collection never returns the raw, mutable collection.

Effective encapsulation of collections avoids requiring specific methods for every collection operation (e.g., `numberOfOrders` instead of `orders.size`). Modern languages offer rich collection classes and standardized interfaces, which are best utilized directly through techniques like 'Collection Pipelines'. Instead, the strategy focuses on allowing controlled access. This can be achieved by returning a read-only proxy of the collection, which forwards read operations but blocks writes by throwing exceptions, a feature available in some languages like Java. Alternatively, and more commonly, the getter returns a copy of the underlying collection, ensuring any modifications to the returned copy do not affect the original encapsulated collection. This approach, while potentially incurring a performance cost for very large collections, is often acceptable for typical list sizes and prevents unintended side effects.

The refactoring process involves ensuring the collection's reference is encapsulated, then adding 'add' and 'remove' functions to the owning class. Any existing setter for the collection should be removed or modified to accept a copy of a new collection. Clients that previously used direct collection modifiers are updated to use the new 'add'/'remove' functions. Finally, the collection's getter is modified to return a protected view, either a read-only proxy or a copy. For instance, in a `Person` class with a `_courses` list, direct modifications like `aPerson.courses.push()` are replaced by `aPerson.addCourse()`. The getter for `courses` would then return `this._courses.slice()` to provide a copy, and the setter would ensure it assigns a copy of the provided list to prevent external references from breaking encapsulation, embodying a 'moderately paranoid' approach to collection management.

📚 Continue Your Learning Journey — No Payment Required

Access the complete Refactoring summary with audio narration, key takeaways, and actionable insights from Martin Fowler, Kent Beck.