Interlude 3. Design Patterns


Interlude 3. Design Patterns

Interlude I3.1 Patterns.

Following is a list of design patterns described in Gamma's Design Patterns . What refactorings might you use to evolve to some of these patterns?

Creational patterns

___ Abstract Factory

___ Builder

___ Factory Method

___ Prototype

___ Singleton

Structural Patterns

___ Adapter

___ Bridge

___ Composite

___ Decorator

___ Fa §ade

___ Flyweight

___ Proxy

Behavioral Patterns

___ Chain of Responsibility

___ Command

___ Interpreter

___ Iterator

___ Mediator

___ Memento

___ Observer

___ State

___ Strategy

___ Template Method

___ Visitor

See Appendix A for solutions.



Section 2: Smells Between Classes

Chapter 8.   Data

Chapter 9.   Inheritance

Chapter 10.   Responsibility

Chapter 11.   Accommodating Change

Chapter 12.   Library Classes

Interlude  4.   Gen-A-Refactoring


Chapter 8. Data

Data can be defined as simple facts, divorced from information about what to do with them. "Data" has a dusty whiff about it, the old-fashioned ring of data processing or data structures .

Data is often a natural starting point for thinking about things. For example, we know we have a first name, middle name, and last name , so we create a Person class with that information. But objects are about data and behavior together ”your code will be more robust if you organize objects by behavior.

Data-oriented objects are an opportunity. The smells in this chapter are often signs of a missing or inadequately formed class. If the data represents a good clustering, we'll usually be able to find behavior that belongs in the class.


Smells Covered

  • Primitive Obsession

  • Data Class

  • Data Clump

  • Temporary Field


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.