Intent: 65 $oshuw - %urzq %:rroi
Intent: 65 $oshuw - %urzq %:rroi
Intent
Avoid coupling the sender of a request to its receiver by giving more than one object a
chance to handle the request. Chain the receiving objects and pass the request along the
chain until an object handles it.
Structure
successor
Client Handler
handleRequest
ConcreteHandler1 ConcreteHandler2
handleRequest handleRequest
A typical object structure and message interaction might look like this:
client
aConcreteHandler
handler aConcreteHandler
successor
successor nil
handleRequest
handleRequest
05/07/97 10:45 1
65 $OSHUW . %URZQ % :RROI
Discussion
Chain of Responsibility is the object-oriented version of recursion, also called recursive
delegation.1 In procedural recursion, a function calls itself with a different parameter
each time. Eventually the parameter is a base case that the function simply performs,
and then the recursion unwinds back to the original call. In recursive delegation, a
method polymorphically sends its message to a different receiver. Eventually the method
invoked is a base case implementation that simply performs the task, and then the recur-
sion unwinds back to the original message send. (Beck, 1997) Chain of Responsibility
explains how to design object structures that use recursive delegation.
The key to Chain of Responsibility is a linked series of objects that recursively pass re-
sponsibility for an operation from one object to the next. When a client makes a request
of one of the objects in the series, that object does its part to implement the behavior,
then passes the buck to the next object in the series. Each object does its part and passes
the buck until eventually an object in the series completes the behavior and returns the
result. The client receives the result without knowing which objects contributed to it.
Tree Chains
Chain of Responsibility occurs most often in Smalltalk in trees, because trees are much
more common in Smalltalk than linked-lists. The structures are related because the path
between the root node in a tree and any leaf node is a linked list. A tree can be linked in
three different ways: the parent points to its children, each child points to its parent, or
both. (See the discussion of tree structures in Composite.) The chain is formed by the
pointers, so the Chain of Responsibility can only travel in the direction of the pointers.
A linked-list or tree might seem like just another way to collect elements, but these
linked structures are quite different from a Collection. A Collection is a two-
layer structure where one object, the Collection itself, knows what all of the ele-
ments in the structure are. Thus is can easily list how many elements there are, what
each of them is, and so forth. A Collection and its elements are related like this:
1
Not all recursive techniques in Smalltalk use Chain of Responsibility, and not all examples
of the pattern are recursive, but recursive delegation is the most common form of object-
oriented recursion and is the Chain of Responsibility pattern.
2 05/07/97 10:45
65 $OSHUW . %URZQ % :RROI
anOrderedCollection anElement1
1
2 anElement2
3
anElement3
aNode1
aNode2
next aNode3
next
next nil
The elements in the linked-list form a chain that Chain of Responsibility recurses
through. The elements in the collection do not form a chain, so Chain of Responsibility
cannot traverse the elements.
Visual Trees
The visual tree structure used to implement a window in VisualWorks contains several
examples of Chain of Responsibility. For more details about the structure of a visual
tree, see Composite.
When a visual computes its bounds (VisualComponent>>bounds), it uses Chain of
Responsibility. Most visuals will draw themselves however large or small they need to
be to fill the area they have. Thus their preferred bounds are unlimited. Yet a visual’s
actual bounds are constrained by the bounds of its container visual, which is constrained
by its container, and so on. Ultimately the window frame constrains the bounds of all of
its components.
Because of this container relationship, a visual does not know its own bounds. Its bounds
depend on what it’s contained in and what the container’s bounds are. The diagram be-
low shows a typical example what happens when a client asks a visual for its bounds.
05/07/97 10:45 3
65 $OSHUW . %URZQ % :RROI
aController
aVisualPart
view aWrapper
container aScheduledWindow
container
bounds
compositionBoundsFor:
compositionBoundsFor: bounds
Let’s look at the implementation of the messages in the diagram. Sending bounds to
the visual runs the implementor in VisualPart.
VisualPart>>bounds
"Answer the receiver's compositionBounds if there
is a container, otherwise answer preferredBounds."
^container == nil
ifTrue: [self preferredBounds]
ifFalse: [container compositionBoundsFor: self]
The instance diagram shows that the VisualPart’s container is not nil, so bounds
sends compositionBoundsFor: to the container. The container is a Wrapper, and
Wrapper inherits compositionBoundsFor: from VisualPart.
VisualPart>>compositionBoundsFor: aVisualPart
"The receiver is a container for aVisualPart.
An actual bounding rectangle is being searched for by
aVisualPart. Forward to the receiver's container."
^container compositionBoundsFor: self
4 05/07/97 10:45
65 $OSHUW . %URZQ % :RROI
This finally returns the bounds for the window and the recursion unwinds.
This simple explanation would seem to imply that any visual’s bounds are the same as
its window’s, but this is not the case. Many visual classes, especially Wrappers
(Decorator visuals), affect their components’ bounds. For example, a Translating-
Wrapper adjusts a visual’s offset from its container by translating its coordinates. It
does this is by specializing the implementation of compositionBoundsFor:.
TranslatingWrapper>>compositionBoundsFor: aVisualPart
^(container compositionBoundsFor: self)
translatedBy: self translation negated
05/07/97 10:45 5
65 $OSHUW . %URZQ % :RROI
A>>initialize
...
B>>initialize
super initialize.
...
C>>initialize
super initialize.
...
D>>initialize
super initialize.
...
6 05/07/97 10:45
65 $OSHUW . %URZQ % :RROI
When a client creates an instance of D and new runs initialize, the implementor of
initialize in D will run the one in C, which in turn runs the implementor in B,
which runs the one in A. This way, each class takes responsibility for implementing its
own part of the object. This is Chain of Responsibility.
Equal, Hash, and Copy
Many common messages in Smalltalk are often implemented using Chain of Responsi-
bility. The messages equal (=), hash, and copy are three examples.
The default implementation of equal in Object is not very interesting. By default,
equal is implemented as double-equal (==). However, structurally complex classes like
those for domain objects often implement equal in a much more interesting way. For ex-
ample, let’s consider how a stereotypical Person object would implement equal. For
the sake of the example, let’s say that two Persons are equal if their names are equal.
Object subclass: #Person
instanceVariables: 'name address phoneNumber'
classVariables: ''
poolVariables: ''
Person>>= aPerson
"Two Persons are equal if their names are equal."
(aPerson isKindOf: Person) ifFalse: [^false].
^self name = aPerson name
PersonName>>= aPersonName
"Two PersonNames are equal if their
first names and last names are equal."
(aPersonName isKindOf: PersonName) ifFalse: [^false].
^(self firstName = aPerson firstName)
and: [self lastName = aPerson lastName]
String>>=
"Two Strings are equal if their characters are equal."
"This example is from VisualWorks."
| size |
aString isString ifFalse: [^false].
aString isSymbol ifTrue: [^false].
(size := self size) = aString size ifFalse: [^false].
1 to: size do:
[:index | (self at: index) = (aString at: index)
ifFalse: [^false]].
^true
05/07/97 10:45 7
65 $OSHUW . %URZQ % :RROI
As this code shows, two Persons are equal if their PersonNames are equal, which
are equal if their first and last name Strings are equal, which are equal if their
Characters are equal. This delegation of equal from Person to PersonName to
String to Character is Chain of Responsibility. Each object takes responsibility for
its part of the computation and then delegates the rest of the responsibility to its appro-
priate attributes.
Any class that implements equal should also implement hash. (Beck, 1997; Woolf;
1996) A class’ implementor of hash works by delegating to the same attributes it dele-
gates equal to. For example, since our Person class delegates equal to its name attrib-
ute, it should do the same for hash:
Person>>hash
"A Person's hash value is the same as its
name's hash value."
^self name hash
Since PersonName uses two attributes for equality, both of them must be hashed and
combined:
PersonName>>hash
"A Person's hash value is a combination of its
parts' hash value."
^self firstName hash bitXor: self lastName hash
So, like equal, Person implements hash using Chain of Responsibility, delegating to
its PersonName, which delegates to its first and last names.
The basic algorithm for an object to create a deep (i.e., fully independent) copy of itself
is this: the object copies itself and all of its parts, which copy themselves and all of their
parts, and so on. This is Chain of Responsibility as well. For a fuller discussion of im-
plementing copy, see the Prototype pattern.
Object-Oriented Trees
One of the most common and powerful techniques you can learn in object-oriented pro-
gramming is “How to implement object-oriented trees.” These trees combine three de-
sign patterns: Composite, Decorator, and Chain of Responsibility. Composite is the
structural pattern that creates trees out of polymorphic nodes. Decorator refines the
structure to enable additional behavior to be added to either a branch or leaf node. And
Chain of Responsibility provides behavior to request that the tree perform a function
without having to know the tree’s structure.
Most Composite structures also contain Decorators. Because Composite breaks a Com-
ponent’s implementation into two subclasses, Composite and Leaf, it is difficult to add
behavior to the Component through subclassing. Subclassing Component won’t work
because the subclass won’t affect Composite or Leaf. Duplicate subclasses of Composite
8 05/07/97 10:45
65 $OSHUW . %URZQ % :RROI
and Leaf are undesirable. Instead, Decorator is a flexible alternative to subclassing that
allows additional behavior to be added to nodes in a structure dynamically. Thus by im-
plementing the extra behavior in a Decorator subclass of Component, you can add the
behavior as a Decorator to a Composite or a Leaf.
Not only are Composite and Decorator convenient to use together, their designs fit to-
gether well. This book’s chapters on Composite and Decorator discuss how the Compo-
nent superclass declares the subclasses’ core interface. The discussions also caution
against extending the core interface in subclasses because that can ruin the polymor-
phism that the client expects. Because of this, classes in either a Composite or Decorator
class tend to have a fairly limited interface that nevertheless provides a full set of func-
tionality. Narrowing the Component’s interface to apply the first pattern (either Com-
posite or Decorator) is difficult, but once it’s been done, applying the second pattern is
much easier. Usually Composite is applied first to define the tree structure. After that,
applying Decorator is relatively easy because Composite has already defined Compo-
nent’s limited core interface.
It is difficult to request a tree to perform a function. As discussed earlier, a tree is not
one object, it is a collection of objects arranged in a hierarchical fashion. Thus for the
tree as a whole to perform a function, it must tell each of its nodes to perform that func-
tion. The procedure to perform the function on all of the tree’s nodes cannot make many
assumptions about the tree’s overall structure since that structure can easily change.
Thus the procedure should let the tree structure itself perform the function on each node.
A procedure that defers to the tree structure is an example of the Chain of Responsibility
pattern.
Thus the Composite, Decorator, and Chain of Responsibility patterns are often used to-
gether. Composite defines object-oriented trees. Having done so, Decorator and Chain of
Responsibility enhance the tree’s functionality and flexibility.
Applicability
Here is when you can and cannot use the Chain of Responsibility pattern:
• Chain already exists. The pattern does not create a chain where there was none.
Design Patterns says it can (page 226), but it’s more accurate to say that the chain
comes from applying a Structural pattern like Composite or Decorator or by simply
implementing a linked structure. The chain might even be a series of Adapters, al-
though it wouldn’t be polymorphic. The chain is either a linked-list or a tree. In a
tree, each path between the root and a leaf—in either direction—is a linked-list.
The pattern uses this existing chain to introduce the new Chain of Responsibility
behavior.
• Collections are not chains. As discussed earlier, a Collection (e.g., an
OrderedCollection or an Array) is not a chain in the sense of this pattern.
05/07/97 10:45 9
65 $OSHUW . %URZQ % :RROI
method’s class
direction initiator recurser terminator
up the tree Leaf, Component, or Client Component Component
down the tree Component or Client Composite Leaf
• Recursing up a tree. A path from a leaf node to the root node in a tree is a
linked-list. The initiator node is a leaf, so the initiator method is implemented
in the Leaf class. If the recursion can start with any node, the initiator method
is implemented in the Component class. The initiator method can also be im-
plemented in a Client class. Since the recursion can travel through any node,
the recurser method is implemented in the Component class. Since any node
10 05/07/97 10:45
65 $OSHUW . %URZQ % :RROI
can act as the root, the terminator method is also implemented in the Compo-
nent class.
• Recursing down a tree. Recursing down a tree from the root node to the leaves
traverses the entire tree, usually depth-first. Thus recursion branches when it
hits a Composite node; i.e., it recurses the path for one child, unwinds, recurses
the path for the next child, unwinds, and so forth for the rest of the children. If
the recursion can start with any node, the initiator method is implemented in
the Component. It can also be implemented in a Client class. The recurser
method is implemented in the Composite class; it continues the recursion by
running the recursion on each of its branches. The terminator method is im-
plemented in the Leaf class; there is usually no reason to move it up into the
Component class.
Sample Code
The File Reader (Woolf, 1996), discussed above, implements a couple of examples of
Chain of Responsibility. It creates a tree to describe the mappings of a record’s fields to
a domain object’s structure and uses a special stream to read the records in as domain
objects.
As a Stream, FormattedStream implements next to read the next record from the
file. next initiates the recursive message readObjectFrom:into: which recurses
down the field format tree and reads the record into a domain object.
Stream subclass: #FormattedStream
instanceVariables: 'dataStream streamFormat ...'
classVariables: ''
poolVariables: ''
FormattedStream>>next
"See superimplementor."
...
^streamFormat readObjectFrom: dataStream
StreamFormatDescription>>readObjectFrom: dataStream
...
dataFieldFormat
readObjectFrom: dataStream
into: resultChannel.
^self result
05/07/97 10:45 11
65 $OSHUW . %URZQ % :RROI
Each kind (subclass) of field format has a different procedure for reading its data out of
the data stream. In the simplest case, a leaf field format reads the data from the next
field, converts it, and stores it in the return object.
FieldFormatDescription subclass: #LeafFieldFormat
instanceVariables: 'readSelector writeSelector'
classVariables: ''
poolVariables: ''
A composite field format reads itself out of the record by recursively reading each of its
child fields out of the record.
FieldFormatDescription subclass: #CompositeFieldFormat
instanceVariables: 'fieldFormats resultChannel
fieldAdaptors'
classVariables: ''
poolVariables: ''
12 05/07/97 10:45
65 $OSHUW . %URZQ % :RROI
CompositeFieldFormat>>readFieldsFrom: dataStream
"Read the fields out of dataStream into the result
object."
1 to: self numberOfFields
do:
[:i |
| field adaptor |
field := self fieldAt: i.
adaptor := fieldAdaptors at: i.
field readObjectFrom: dataStream into: adaptor]
A decorator field format simply forwards the read request to its component.
FieldFormatDescription subclass: #FieldFormatDecorator
instanceVariables: 'fieldFormat'
classVariables: ''
poolVariables: ''
05/07/97 10:45 13
65 $OSHUW . %URZQ % :RROI
14 05/07/97 10:45