Retreaded: CourtesyImplementation
Retread of post orginally made on 12 Aug 2004
When you a write a class, you mostly strive to ensure that the
features of that class make sense for that class. But there are
occasions when it makes sense to add a feature to allow a class to
conform to a richer interface that it naturally should.
The most common and obvious example of this is one that comes up
when you use the composite pattern. Let's consider a simple example
of containers. You have boxes which can contain other boxes and
elephants (that's an advantage of virtual elephants.) You want
to know how many elephants are in a box, considering that you need
to count the elephants inside boxes inside boxes inside the box. The
solution, of course, is a simple recursion.
# Ruby
class Node
end
class Box < Node
def initialize
@children = []
end
def << aNode
@children << aNode
end
def num_elephants
result = 0
@children.each do |c|
if c.kind_of? Elephant
result += 1
else
result += c.num_elephants
end
end
return result
end
end
class Elephant < Node
end
Now the kind_of? test in num_elephants is a smell, since we
should be wary of any conditional that tests the type of an
object. On the other hand is there an alternative? After all we are
making the test because elephants can't contain boxes or elephants, so it doesn't
make sense to ask them how many elephants are inside them. It
doesn't fit our model of the world to ask elephants how many
elephants they contain because they can't contain any. We might say
it doesn't model the real world, but my example feels a touch too
whimsical for that argument.
However when people use the composite pattern they often do
provide a method to avoid the conditional - in other words they do
this.
class Node
#if this is a strongly typed language I define an abstract
#num_elephants here
end
class Box < Node
def initialize
@children = []
end
def << aNode
@children << aNode
end
def num_elephants
result = 0
@children.each do |c|
result += c.num_elephants
end
return result
end
end
class Elephant < Node
def num_elephants
return 1
end
end
Many people get very disturbed by this kind of thing, but it does
a great deal to simplify the logic of code that sweeps through the
composite structure. I think of it as getting the leaf class
(elephant) to provide a simple implementation as a courtesy to its
role as a node in the hierarchy.
The analogy I like to draw is the definition of raising a number
to the power of 0 in mathematics. The definition is that any number
raised to the power of 0 is 1. But intuitively I don't think it
makes sense to say that any number multiplied by itself 0 times is
1 - why not zero? But the definition makes all the mathematics work
out nicely - so we suspend our disbelief and follow the definition.
Whenever we build a model we are designing a model to suit how we
want to perceive the world. Courtesy Implementations are worthwhile
if they simplify our model.
reposted on 27 Aug 2014
Martin Fowler's Blog
- Martin Fowler's profile
- 1099 followers
