1
Design Patterns in Smalltalk
CSC591O April 9, 1997 Raleigh, NC
Copyright (C) 1997, Kyle Brown, Bobby Woolf, and Knowledge
Systems Corp. All rights reserved. 2
Bobby Woolf
Senior Member of Technical Staff Knowledge Systems Corp.
4001 Weston Parkway Cary, North Carolina 27513-2303
919-677-1116 bwoolf@ksccary.com
3
Why Design Patterns and
Smalltalk?
ODesign Patterns help explain Smalltalk’s extensive class libraries
» Lots of examples in vendor-provided code
OSmalltalk raises programmers above the bits & bytes level
» They can think about design rather than implementation
4
Design Patterns for Review
OTemplate Method (325) OComposite (163) ODecorator (175) OChain of Responsibility (223) OAdapter (139) OObserver (293)
Designing for Extension
ODesigning classes that are meant to be subclassed is HARD
» Especially when they are concrete classes themselves OOften you want to let a
superclass control the way its subclasses will operate
» The Hollywood principle
Template Method (325)
ODefine the outline of an algorithm in an abstract superclass
ODefer some steps to subclasses OSubclasses specialize the algorithm by
overridding abstract methods OTemplate Method uses three types of
methods
» Concrete operations » Abstract (primitive) operations
7
Template Method Structure
AbstractClass templateMethod primitiveMethod1 primitiveMethod2 ConcreteClassA primitiveMethod1 primitiveMethod2 ConcreteClassB primitiveMethod1 primitiveMethod2 ConcreteClassC primitiveMethod1 ... self primitiveMethod1. ... self primitiveMethod2. ... 8Template Method Example
Object>>printString
"Answer a String that is an ASCII representation of the receiver."
| aStream aString | aString := String new: 20.
self printOn: (aStream := WriteStream on: aString). ^aStream contents
printOn: is a hook method printString is a Template Method
9
Template Method Example
Object>>printOn: aStream
"Append the ASCII representation of the receiver to aStream. This is the default implementation which prints 'a' ('an') followed by the receiver class name."
| aString |
aString := self class name. (aString at: 1) isVowel
ifTrue: [aStream nextPutAll: 'an '] ifFalse: [aStream nextPutAll: 'a ']. aStream nextPutAll: aString
This is the “default” printOn: implementation
10
Template Method Example
String>>printOn: aStream
"Append the receiver as a quoted string to aStream doubling all internal single quote characters."
aStream nextPut: $'. self do:
[ :character |
aStream nextPut: character. character = $'
ifTrue: [aStream nextPut: character]]. aStream nextPut: $'
so 'abc' printString yields 'abc', not aString
Benefits of Template Method
OMakes classes easier to subclass and specialize
» Simpler, smaller methods
OOften arises when refactoring common behavior from subclasses
» “Refactoring to Generalize”
Object-Oriented Trees
OThe next three patterns are commonly used together in OO programs in tree structures OThe structure of the algorithms involved is
13
OO Trees (Top-Down)
aBranch aBranch aLeaf aLeaf aLeaf 14OO Trees (Bottom-up)
aBranch aBranch aLeaf aLeaf aLeaf 15OO Trees (doubly-linked)
aBranch aBranch aLeaf aLeaf aLeaf 16Whole-part structures
O Example: Financial portfolio composed of individual stocks and bondsO You would like to have both the portfolio and the individual stocks and bonds act alike in some ways
Composite (163)
OCompose objects into tree structures to represent part-whole hierarchies OLets clients treat individual objects and
compositions of objects uniformly
OAbstract class represents both primitives and their containers
Composite Structure
Leaf AbstractComponent Composite N N19
Typical Composite
aComposite
aLeaf aComposite aLeaf
aLeaf aLeaf 20
Composite in VisualWorks
VisualComponent VisualPart DependentPart View TranslatingWrapper BoundedWrapper CompositePart DependentComposite CompositeView BorderedWrapper Wrapper 21Adding new behavior
O Sometimes you need to customize the behavior of an object at runtime
» Subclassing not an option O Example: adding
borders or scroll bars to a View
22
Decorator (175)
OAlso known as: WrapperOAttach additional responsibilities to an object dynamically
OA flexible alternative to subclassing for extending functionality
OForwards requests to the component, may perform additional actions
OMay be nested recursively
Decorator Structure
Leaf AbstractComponent Decorator 1Decorator in VisualWorks
VisualComponent VisualPart DependentPart View TranslatingWrapper BoundedWrapper CompositePart DependentComposite CompositeView Wrapper25
Using Tree Structures
O How do you handle requests made to an OO tree?
» Who is responsible for doing the work? » A tree is NOT an object
--it’s a collection of objects O Example: Context
sensitive help system
26
Chain of Responsibility (223)
OAvoid coupling the sender of a request to itsreceiver
ORequest passes through multiple handlers until one handles it
OHandler should be ascertained automatically
» Who handles request is not determined until request is processed
OSet of handlers is dynamic
27
Chain of Responsibility Structure
ConcreteHandler1 handleRequest ConcreteHandler2 handleRequest Client Handler handleRequest successor 28
Chain of Responsibility (object)
client handler aConcreteHandler handler aConcreteHandler handler nil
Chain of Responsibility
(message)
client aConcrete Handler another ConcreteHandler handleRequest handleRequestChain of Responsibility
(example)
aController view aVisualPart container aScheduledWindow aWrapper container31
Chain of Responsibility
(example)
aController aVisualPart bounds compositionBoundsFor: aWrapper compositionBoundsFor: aScheduled Window bounds 32Incompatible Interfaces
O Often you have two objects with
incompatible interfaces that need to work together
O Example: Electrical Voltage Adaptor
33
Adapter (139)
OAlso known as: WrapperOConverts the interface of a class into another interface clients expect
OLets classes with incompatible interfaces work together
OAdapter can add functionality the Adaptee doesn’t provide
OEnables use of several existing subclasses
34
Adapter (Structure)
Adapter request Adaptee specificRequest Client TargetInterface request OtherTargetImplementor request adaptee specificRequest (interface) adapteeMaintaining Consistent State
O Often you have several objects that need to be kept consistent with the state of another object
O Example: multiple windows showing different views of the same object
Observer (293)
OAlso known as: Dependents, Publish-Subscribe
ODefine a one-to-many dependency
» When one object changes state, all dependents are notified automatically
» Dependents can update automatically
ODecouples Subject from Observer
37
Observer Structure
Subject addDependent: removeDependent: changed: Observer update: dependents ConcreteObserver observerState update: ConcreteSubject subjectState subjectState subjectState: subjectself observerState: self subject subjectState
^subjectState dependents do:[obs | obs update: aSymbol] 38
Observer (object)
aConcreteSubject dependents aConcreteObserver1 subject aConcreteObserver2 subject 39Observer (interaction)
aConcreteSubject aConcreteObserver1 aConcreteObserver2
subjectState: anObject changed: aSymbol update: aSymbol subjectState update: aSymbol subjectState 40
Summary
OTemplate Method (325) helps you define superclasses for extension
OComposite (163) helps you build whole-part structures
ODecorator (175) shows how to extend the behavior of runtime objects
Summary (2)
OChain of Responsibility (223) handles requests in OO trees
OAdapter (139) resolves incompatible interfaces
OObserver (293) provides efficient 1-N notification