Message Sends are Plans for Reuse

Damien Cassou, St├ęphane Ducasse and Luc Fabresse http://stephane.ducasse.free.fr

About This Lecture

Another design lecture:

What You Will Learn

Sending A Message Leads to a Choice

An Example

Node >> setWindowWithRatioForDisplay
   | defaultNodeSize |
   defaultNodeSize := mainCoordinate / maximizeViewRatio.
   self window add:
      (UINode new
         with: bandWidth * 55 / defaultWindowSize).
   previousNodeSize := defaultNodeSize.

We want to change the defaultNodeSize formula in a subclass

Duplication

Duplicate the code in a subclass

Node subclass: OurSpecificNode
   ...
OurSpecificNode >> setWindowWithRatioForDisplay
  | defaultNodeSize |
  defaultNodeSize :=
     (mainCoordinate / maximizeViewRatio) + 10.
  self window add:
      (UINode new
         with: bandWidth * 55 / defaultWindowSize).
  previousNodeSize := defaultNodeSize.

Avoid Duplication

Solution

  • send messages
  • define small methods

Subclasses can override such methods

We can Refactor this

Node >> setWindowWithRatioForDisplay
  | defaultNodeSize |
  defaultNodeSize := (mainCoordinate / maximizeViewRatio).
  self window add:
      (UINode new
         with: bandWidth * 55 / defaultWindowSize).
  previousNodeSize := defaultNodeSize.

Better Design

Node >> setWindowWithRatioForDisplay
   | defaultNodeSize |
   defaultNodeSize := self ratio.
   self window add:
      (UINode new
         with: bandWidth * 55 / defaultWindowSize).
   previousNodeSize := defaultNodeSize.

Node >> ratio
   ^ mainCoordinate / maximizeViewRatio

Subclasses Reuse Superclass Logic

Node >> ratio
   ^ mainCoordinate / maximizeViewRatio

A subclass can refine the behavior

OurSpecificNode >> ratio
   ^ super ratio + 10

Another Step

Node >> setWindowWithRatioForDisplay
   | defaultNodeSize |
   defaultNodeSize := self ratio.
   self window add:
      (UINode new
         with: bandWidth * 55 / defaultWindowSize).
   previousNodeSize := defaultNodeSize.

We can also extract the UINode instantiation.

Another Step

Node >> setWindowWithRatioForDisplay
   | defaultNodeSize |
   defaultNodeSize := self ratio.
   self window add: self uiNode.
   previousNodeSize := defaultNodeSize.
Node >> uiNode
   ^ UINode new
      with: bandWidth * 55 / defaultWindowSize

Do Not Hardcode Class Use

Node >> uiNode
   ^ UINode new
      with: bandWidth * 55 / defaultWindowSize

Define Methods Returning Classes

Node >> uiNode
   ^ self uiNodeClass new
      with: bandWidth * 55 / defaultWindowSize.
Node >> uiNodeClass
   ^ UINode

Many Small Messages

Small messages are a sign of good design

Avoid Magic Numbers

Node >> uiNode
   ^ self uiNodeClass new
      with: bandWidth * 55 / defaultWindowSize.

Use a Message Send

Node >> uiNode
   ^ self uiNodeClass new
      with: bandWidth * self averageRatio / defaultWindowSize.

Node >> averageRatio
   ^ 55

How to let the class users change the value?

Use an Instance Variable

Node >> averageRatio
   ^ averageRatio ifNil: [ self defaultAverageRatio ]
Node >> defaultAverageRatio
   ^ 55
Node >> averageRatio: aNumber
   averageRatio := aNumber

Gruyere-Oriented Programming

.

Conclusion

/