7 - Polymorphic Hierarchy
7 - Polymorphic Hierarchy
Bobby Woolf
Ive noticed that at least half the methods I write are not very original. Sure, lots of the methods I write
are real methods that do real work and have real names that are fairly unique. Yet in the process of that
real programming, I also write a ton of methods that dont require much thought. I implement lots of
getter and setter methods, initialization and instance creation methods, and I write a fair number of
methods that subimplement methods already defined in a superclass. Im finding that it is these
subimplementor methods that are the key to polymorphism. Used aggressively and consistently,
polymorphic methods lead to polymorphic classes and ultimately polymorphic hierarchies.
Ill discuss what a polymorphic hierarchy is as well as a pattern I call Template Class. The top class in a
polymorphic hierarchy is a Template Class.
5/18/1996 08:45:00 PM
Polymorphic Hierarchy
Bobby Woolf
5/18/1996 08:45:00 PM
Polymorphic Hierarchy
Bobby Woolf
or what? Subclasses of Collection implement the details of how. Set (a hash table) implements
add:, remove:, do:, and size one way. OrderedCollection (a list) implements them another
way. Collection defines what a collection can do; the subclasses define how that gets done.
How do I make sure that the subclass does the same thing the superclass does? Each method that the
subclass subimplements (extends or overrides from the superclass) has to do the same thing as the method
in the superclass does. The subimplementor doesnt do it the same way, of course, but it should produce
the same result. In other words, the subimplementor should have the same purpose as the
superimplementor.
Purpose is polymorphic
When all implementors in a hierarchy have the same purpose, theyre polymorphic. When all of the
methods that subclasses subimplement are polymorphic with their inherited versions, the hierarchy is
polymorphic. This means that a collaborating object can use one instance of the hierarchy just as easily as
another instance. Because all of the instances behave the same, one works just as well as another.
For example, consider an object (Employee) that should maintain a list of things to do (toDoList).
How should the object sort the list, by priority or first-come-first-serve? Who knows? But you know it will
be some sort of Collection, probably either an OrderedCollection or a SortedCollection.
So however you eventually decide to implement the toDoList, you already know what its behavior is.
You can add a task to be done (add:), remove a task thats been done (remove:), ask how many tasks
there are left to do (size), and ask for the next one to do (first). Later you can work out the more
domain-specific details of how the list should be ordered and use an OrderedCollection or
SortedCollection as appropriate.
Defining polymorphism
This definition of polymorphism is more extensive than the ones you usually hear. The sound-bite
definition I learned was that two methods are polymorphic if their names are the same. This is clearly not
always true. Think about the messages value and value:. They have lots of implementors, but are
those implementors polymorphic? If they are polymorphic, what do those messages do? That depends on
the receiver. In a ValueModel, value and value: are accessor (getter and setter) methods. In a block
(a BlockClosure), value and value: are evaluation methods, clearly not getters and setters. These
implementors of value and value: have the same name, but they are not polymorphic.
For two methods to be polymorphic, they not only need to have the same name, they must behave the
same way as well. This means that they not only accept the same number of parameters, but each
parameter is of the same type in both methods. Both methods must produce the same side effects, such as
changing the state of the receiver in the same way. And both methods must return the same type of result.
Only then are the two methods truly polymorphic.
As described earlier, I contend that two classes can be polymorphic. Two polymorphic classes understand
the same messages and their implementors of those messages are polymorphic. Since the two classes share
the same interface and behave the same way, they are polymorphic. In practice, two classes often do not
share the same complete interface, but they do share the same core interface and it is polymorphic. A core
interface is an interface that several classes share so that they can be used interchangeably. As long as a
collaborator only uses that core interface, it can use an instance of one class as easily as any other class
that has the core interface.
5/18/1996 08:45:00 PM
Polymorphic Hierarchy
Bobby Woolf
The problem comes when there is no superimplementor to see. Sometimes Im implementing a method
and I remember that Ive already implemented another method with the same name. Theyre doing the
same thing, so they have the same purpose. If one of them is a subimplementor of the other, I describe the
subimplementor with See superimplementor. But I cant do this when they are in peer classes and there
is no superimplementor. When this happens, the code is telling me, Youre missing a superimplementor.
I dont want to duplicate any effort I can avoid. This includes defining what this message is supposed to do
in this hierarchy. So I introduce a superimplementor, document the purpose in there, and give it a default
implementation. Now I can document the subimplementors with See superimplementor.
Of course, another problem I sometimes run into is that theres no superclass to put the superimplementor
in. Two classes with two supposedly polymorphic implementations of the same message are peer classes
that have no relationship to each other in the hierarchy. Their first common superclass is something
generic like ApplicationModel or Object. Im definitely not going to add this domain-specific
message to such a general class, as though all subclass should support this message, so what can I do? If
these two implementors are really polymorphic, then their classes are probably going to need to be
polymorphic as well. If so, the most maintainable way to make two classes polymorphic is to put them in
the same hierarchy and make the whole hierarchy polymorphic. Since this hierarchy does not exist, I need
to create a new abstract class that describes the polymorphic behavior of this hierarchy, then subclass my
two concrete classes off of it. The hierarchy now exists, so now I can add the superimplementor to the
superclass. The purpose of the message goes in the superimplementor and the subimplementors just say
See superimplementor.
Conclusion
To summarize:
Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns: Elements of
Reusable Object-Oriented Software. Addison-Wesley, Reading, MA, 1995, ISBN 0-201-63361-2;
http://www.aw.com/cp/Gamma.html.
5/18/1996 08:45:00 PM
Polymorphic Hierarchy
Bobby Woolf
A lot of methods not only have the same name, they do the same thing. This is where polymorphism
comes from.
For two methods to be polymorphic, they need to have not only the same name, but also the same
parameter types, the same side-effects, and the same return type.
Two methods that are polymorphic should appear in the same method protocol.
A method description documents two things: the purpose and the implementation details.
For two methods to be polymorphic, they need to have the same purpose. They should not have the
same implementation details.
For two classes to be polymorphic, they need to share the same core interface of polymorphic
messages.
A collaborator can use the two classes interchangeably if it only uses messages in their core interface.
For a hierarchy to be polymorphic, all of its classes must share the same polymorphic core interface.
The polymorphic hierarchy and its core interface is defined by an abstract class. I call an abstract
class which fulfills this role a Template Class.
A polymorphic hierarchy encapsulates code that is highly reusable, flexible, extensible, and just plain
good OO.
To learn more about implementing your own polymorphic hierarchies, I suggest reading the paper
Reusability Through Self-Encapsulation by Ken Auer. 2 It is a pattern language that describes how to
develop a class hierarchy that achieves reuse via inheritance while maintaining each class encapsulation.
Although polymorphism is not an explicit goal of the pattern language, hierarchies developed this way
tend to be polymorphic ones.
-------------------Bobby Woolf is a Senior Member of Technical Staff at Knowledge Systems Corp. in Cary, North Carolina.
He mentors clients in the use of VisualWorks, ENVY, and design patterns. He welcomes your comments at
[email protected] or at http://www.ksccary.com.
-------------------The key to polymorphism is separate methods that not only have the same name but also do the same
thing. However, polymorphic methods are not enough. They must be clustered together into polymorphic
classes that form polymorphic hierarchies. Bobby explores how polymorphic hierarchies emerge during
the development process.
-------------------The description for a polymorphic subimplementor is, See superimplementor.
A method description has two parts: purpose and implementation details.
A methods purpose is reusable; its implementation details is not.
The See superimplementor description makes developers think polymorphically.
Coplein, James and Douglas Schmidt, Editors. Pattern Languages of Program Design. Addison-Wesley,
Reading, MA, 1995, ISBN 0-201-60734-4;
http://heg-school.aw.com/cseng/authors/coplien/patternlang/patternlang.html.
5/18/1996 08:45:00 PM