Navigation:  Appendix B: Dolphin Pattern Book > Class Patterns >

Instance Variable Role

Previous pageReturn to chapter overviewNext page

Context

You are creating a New Class and have to choose the variables that each instance will possess. The state of an object is defined by the values of its instance variables. It is important to know what role a particular instance variable performs in a class, as this will affect when and how it is initialized and used. How do we determine an instance variable's role?

Solution

Instance variables can be divided into one of three main roles as follows:

1.Identity
Identity instance variables hold information which uniquely identifies the object. Identity variables are set very early in the lifetime of the object, generally by using an Instance Creation Method. Once they are set they do not change during the lifetime of an object.
2.State
State instance variables represent the attributes (or properties) of an object. Together, they define the status of an object. They can be set by any combination of Instance Initialization, Lazy Initialization or Accessor Methods.
3.Caching
Caching instance variables hold the result of a (usually time consuming) calculation involving Identity or State instance variables. If the Identity or State variables are subsequently changed, then the cache variable must be recalculated. Cache variables are usually calculated on demand using Lazy Initialization. The cache variables should have "calculate" and "clear" methods as described in the example below.

Examples

Imagine a class Cylinder which represents a 3D cylinder. It has two State variables radius and height, and a Cache variable volume which is calculated from radius and height.

Object subclass: #Cylinder

  instanceVariableNames: 'radius height volume'

  classVariableNames: ''

  poolDictionaries: ''

  classInstanceVariableNames: ''

 

volume is accessed using Lazy Initialization.

volume

  volume isNil ifTrue: [

      volume := Float pi * radius squared * height ].

  ^volume

 

Whenever radius or height are changed, volume is set to nil so that it will be re-calculated when it is next required.

radius: aNumber

  radius := aNumber.

  self clearVolume.

 

height: aNumber

  height := aNumber.

  self clearVolume.

 

clearVolume

  volume := nil.

 

Known Uses

The initialization method #name:length in the sample VideoTape class illustrates the difference between State and Identity instance variable roles.

name: tapeName length: tapeLength

  "Private - Initialize the receiver with the <readableString> tapeName and

  the <Integer> length in minutes.

  Illustrated Patterns:

  Instance Initialization

  Instance Variable Role

  Private Method

  "

  name :=  tapeName.

  length := tapeLength.

  recordings := OrderedCollection new.

 

The method is marked as private because it is not intended that it be called outside of the initialization phase of the receiver. This in turn implies that the name and length instance variables cannot be altered once an instance has been born. Hence these can be considered to be Identity instance variables since they uniquely identify the video tape object compared to all other instances of VideoTape.

The recordings variable can be altered throughout the lifetime of the tape and so is considered to be a State instance variable.

Related Patterns

Temporary Variable Role