Primitive Obsession


Primitive Obsession

Symptoms

Look for:

  • Uses of the primitive or near-primitive types ( int , float , String , etc.)

  • Constants and enumerations representing small integers

  • String constants representing field names

Causes

Several things can cause overuse of primitives:

  • Missing class: Since almost all data must be in a primitive somewhere, it's easy to start with a primitive and miss an opportunity to introduce a new class.

  • Simulated types: Some primitives act as type codes, in effect, simulating objects. A class may start with one behavior, then pick up a boolean to say which of two behaviors are used, and then there may be an enumeration of small values to say which of several behaviors to use. But by then, it may well be hiding a need for multiple classes.

  • Simulated field accessors: Sometimes a primitive is used as an index to provide access to pseudofields in an array. Strings are occasionally used this way with HashTables or Maps.

What to Do

For missing objects :

  • See Data Clump (this chapter), because the primitives can often be encapsulated by addressing that problem.

  • Replace Data Value with Object to make first-class data values.

For simulated types , an integer type code stands in for a class.

  • If no behavior is conditional on the type code, then it is more like an enumeration, so Replace Type Code with Class.

  • If the type code is immutable and the class is not subclassed already, Replace Type Code with Subclass.

  • If the type code changes or the class is subclassed already, Replace Type Code with State/Strategy. In Fowler's Refactoring , there's an example of this transformation in the description of Replace Conditional with Polymorphism .

For simulated field accessors :

  • If the primitive is used to treat certain array elements specially, Replace Array with Object.

Payoff

Improves communication. May expose duplication. Improves flexibility. Often exposes the need for other refactorings.

Contraindications

  • Primitives that are really missing objects are so common that I hesitate to provide any excuses for not introducing the object. There are occasionally dependency or performance issues that stop you from addressing this smell.

  • A Map can sometimes be used instead of an object with fixed fields, by using the names of fields as indices. This can reduce coupling to the structure of a simple object, but at some cost in performance, type safety, and clarity.

Notes

  • A close relative of this problem occurs when ArrayList (or some other generic structure) is overused .

EXERCISE 24 Alternative Representations.

Suggest two or three alternative representations for each of these types.

Money:

Position (in a list):

Range:

Social Security Number (government identification number: "123-45-6789"):

Telephone number:

Street Address ("123 E. Main Street"):

ZIP (postal) code:

See Appendix A for solutions.

EXERCISE 25 A Counterargument.

Consider a business application in which a user enters a ZIP code (among other things) and it gets stored in a relational database. Someone argues: "It's not worth the bother of turning it into an object; when it gets written, it will just have to be turned into a primitive again." Why might it be worth creating the object in spite of the need for two conversions?

See Appendix A for solutions.

EXERCISE 26 Iterator.

How does an Iterator or Enumerator reduce primitive obsession?

See Appendix A for solutions.

EXERCISE 27 Editor.

Consider this interface to an editor:

 public class Editor {    public void insert(String text) {...}    public String fetch(int numberOfCharactersToFetch) {...}    public void moveTo(int position) {...}    public int position() {...}    // more, omitted } 

and this sequence of calls:

 editor.insert("ba(nana)");    int firstParendPosition = 2;    editor.moveTo(firstParendPosition);    assertEquals("(", editor.fetch(1));    editor.moveTo(1);    editor.insert("x");   // Now: bxa(nana)    editor.moveTo(firstParendPosition);    assertEquals(___, editor.fetch(1)); 
  1. Given the interface provided, what string would you expect to use in place of the ___?

  2. Based on the variable name (firstParendPosition) , what string might you like to use instead? Of what use would this be?

  3. The crux of the problem is the use of int as a position index. Suggest an alternative approach.

  4. Relate your solution to the Memento design pattern (from Gamma's Design Patterns ).

See Appendix A for solutions.




Refactoring Workbook
Refactoring Workbook
ISBN: 0321109295
EAN: 2147483647
Year: 2003
Pages: 146

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net