From "Refactoring"
🎧 Listen to Summary
Free 10-min PreviewReplace Primitive with Object
Key Insight
Simple data types, such as numbers or strings, often start as primitive values but evolve to require specialized behavior. For example, a string representing a telephone number may eventually need formatting, area code extraction, or validation. Without a dedicated object, this logic becomes duplicated across the codebase, making maintenance and evolution challenging. The 'Replace Primitive with Object' refactoring addresses this by converting a primitive data item into its own class. This new class serves as a centralized place for all behavior specific to that data item, even if initially it merely wraps the primitive value.
This refactoring is considered highly valuable by experienced developers because these 'value objects' can grow to encapsulate significant logic, improving code clarity and reducing duplication. The mechanics begin with encapsulating the primitive variable if it isn't already, typically using 'Encapsulate Variable'. A new, simple value class is then created, accepting the existing primitive value in its constructor and providing a getter. The original setter is modified to create and store an instance of this new value class, while the getter is adjusted to return the result of invoking the new class's getter. It is also beneficial to rename the original accessors to accurately reflect what they return, for example, changing 'priority' to 'priorityString' if it now returns a string representation of a priority object.
An example involves an `Order` class with a string `priority` ('high', 'rush'). Initially, client code filters orders based on string comparisons. After encapsulating the variable, a `Priority` class is introduced with a constructor and a `toString()` method. The `Order`'s `priority` setter then creates a `new Priority(aString)`, and its getter returns `this._priority.toString()`. A new getter, `get priority()`, can be added to return the `Priority` object directly, allowing clients to use it. The `Priority` class can then be extended with validation (`Priority.legalValues()`) and comparison methods (`equals()`, `higherThan(other)`, `lowerThan(other)`), transforming client code from string comparisons like `o => 'high' === o.priorityString` to object-oriented comparisons such as `o => o.priority.higherThan(new Priority('normal'))`, thus making the code more meaningful and robust.
📚 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.