Main >> showHappiness: animal
animal isDog
ifTrue: [ animal shakeTail ].
animal isDuck
ifTrue: [ animal quack ].
animal isCat: [ ... ].
Branching (with if
) based on the type of an object is bad:
Send messages instead
Dog >> showHappiness
self shakeTail
Duck >> showHappiness
self quack
Cat >> showHappiness
...
Branching (with if
) based on the type of an object is bad
Send messages instead
Inferencer >> rulesForFact: aFact
self noRule ifTrue: [ ^ nil ]
^ self rulesAppliedTo: aFact
ifTrue: [ ^ nil ]
forces every client to check for nil
:
(inferencer rulesForFact: 'a')
ifNotNil: [ :rules |
rules do: [ :each | ... ]
When possible, replace if
by polymorphic objects:
Inferencer >> rulesForFact: aFact
self noRule ifTrue: [ ^ #() ]
^ self rulesAppliedTo: aFact
Your clients can just iterate and manipulate the returned value
(inferencer rulesForFact: 'a')
do: [:each | ... ]
For exceptional cases, replace nil
by exceptions:
if
in clientsFileStream >> nextPutAll: aByteArray
canWrite ifFalse: [ self cantWriteError ].
...
FileStream >> cantWriteError
(CantWriteError file: file) signal
Avoid nil
checks by initializing your variables
nil
Archive >> initialize
super initialize.
members := OrderedCollection new
You can defer initialization of a variable to its first use:
FreeTypeFont >> descent
^ cachedDescent ifNil: [
cachedDescent := (self face descender * self pixelSize //
self face unitsPerEm) negated ]
Sometimes you have to check before doing an action
ToolPalette >> nextAction
self selectedTool
ifNotNil: [ :tool | tool attachHandles ]
ToolPalette >> previousAction
self selectedTool
ifNotNil: [ :tool | tool detachHandles ]
NoTool >> attachHandles
^ self
NoTool >> detachHandles
^ self
ToolPalette >> initialize
self selectedTool: NoTool new
ToolPalette >> nextAction
self selectedTool attachHandles
ToolPalette >> previousAction
self selectedTool detachHandles
if
/