This chapter presents the third and last case study of this
dissertation: the JHotDraw framework for building graphical drawing
editor applications. JHotDraw has several framework predecessors,
most notably the Smalltalk framework of same name (HotDraw) and
ET++. Also, an expert developer (Erich Gamma), who uses it for
teaching purposes, developed JHotDraw. As a consequence, JHotDraw
is a very mature framework. This chapter presents the framework
starting out with a class-based design as gathered from the documentation.
It then adds a role modeling interpretation to the existing design
and thereby shows that role modeling adds crucial information
that would otherwise be missed. The catalog of role model patterns
was used in this work. Finally, this chapter consolidates its
observations and relates them to the problems driving this dissertation.
8.1 Case study overview
JHotDraw is an application framework for building graphical
drawing editor applications. It is a mature Java framework that
is publicly available. The case study presented in this chapter
discusses the core classes of the framework and shows how role
modeling helps in its documentation.
8.1.1 JHotDraw history
Users use drawing editors to visually arrange graphical figure
objects on a drawing area. Drawing editors are a common type of
application, found on nearly every computer desktop. However,
the type of figures may significantly vary. Some drawing editors
are more like painting applications, allowing users to draw paintings.
Other drawing editors cover a specific domain, so that the figures
users manipulate reflect the semantics of the domain. Examples
of the later are drawing editors for technical drawings in specific
application domains like architecture or manufacturing.
JHotDraw is an application framework that can be used for developing
custom-made drawing editor applications. Each application is targeted
at a specific domain and reflects the domain's semantics by providing
specific figure types and by observing their relationships and
constraints.
JHotDraw was developed by Erich Gamma. The current version,
on which this case study is based, is 5.1. It is a mature framework,
and it is publicly available (see Appendix E for a pointer). This
makes it an ideal candidate for a case study in a dissertation.
JHotDraw itself is based on a long history of drawing editor
frameworks. In particular, JHotDraw is the Java version of an
earlier Smalltalk framework, called HotDraw [Joh92]. Hotdraw is
also publicly available (again, see Appendix E for a pointer).
In addition, JHotDraw draws on its developer's background with
ET++, an early C++ application framework [WGM89, WG95].
Erich Gamma uses JHotDraw for teaching purposes (which is one
reason, why it is a well-designed and implemented framework).
The code is annotated (using JavaDoc-style comments). Also, a
tutorial exists, which discusses the major design issues of the
framework [BG98].
In the following, we refer to this set of information (source
code, code annotations and comments, and the tutorial) as the
JHotDraw documentation. It is not a complete documentation (it
is not meant to be complete). This does not represent a problem,
because the case study does not attempt to provide a complete
documentation of JHotDraw either.
8.1.2 The case study
The case study walks through the major design aspects of the
JHotDraw framework. It categorizes them into three parts: a first
part on the Figure class hierarchy, a second part on the Drawing
and DrawingView classes, and a third part on the DrawingEditor
classes.
Each part is presented in two forms. First, the design is described
using the information available from the existing documentation.
Each part starts with the class documentation from JavaDoc and
relates it to the design documentation from the tutorial. This
gives a fairly complete picture of the design under discussion.
To make things complete, each part adds information from the source
code that is missing from the documentation.
A second part then uses role modeling to describe the role-model-based
class model of the design. This revised class model is the result
of reading the JHotDraw documentation and implementation and deriving
the role models from it. While the first part provides us with
a traditional documentation, enhanced with pattern annotations,
the second part provides us with a role modeling view of the design.
This partitioning lets us compare the role-model-based version
of the class model with the original class model. The evaluation
section at the end of the chapter uses this comparison to derive
arguments about the suitability of using role modeling for framework
design and documentation.
In the final section, the case study first reports about the
observations made during determining the role-model-based documentation
of the class model. These observations are then related to the
problems in framework design that are driving this dissertation.
8.1.3 Chapter structure
The next section presents the JHotDraw framework. It starts
with an overview, and then walks through the three major design
parts. The final section presents the observations made during
this design documentation and relates them to the framework design
problems stated in Chapter 1 and 2.
8.2 The JHotDraw framework
This section describes the JHotDraw application framework for
graphical drawing editors. It first gives an overview of the design,
and then splits it up into three parts: one on the Figure class
hierarchy, one on the Drawing and DrawingView classes, and one
on the DrawingEditor and associated functionality classes.
8.2.1 Design discussion overview
Figure 8-1 shows the class model of the JHotDraw drawing editor
framework (as far as discussed in this case study; this is not
a complete model). It lists all classes relevant for the discussion
and shows their structural relationships. This class model stems
from the JHotDraw tutorial, so we are following Kent Beck and
Erich Gamma in picking these classes as the most interesting ones
for communicating the JHotDraw (interface) architecture.
-
-
- Figure 8-1: The class model of core JHotDraw classes (as
chosen for the case study).
The overall design discussion is divided into three parts.
The following subsections discuss each part.
- The Figure classes. This part describes the Figure class
hierarchy and associated classes. It discusses the Figure, CompositeFigure,
DecoratorFigure, ConnectionFigure, Connector, and Handle classes.
- The Drawing and DrawingView classes. This part describes
the use of Figure objects in the context of a drawing and its
display in a drawing view. It discusses the Drawing, DrawingView,
DrawingEditor, and Painter classes.
- The DrawingEditor classes. This part describes the overall
drawing editor functionality. It discusses the DrawingEditor,
the Tool, CreationTool, HandleTracker, and SelectionTool classes,
and the Handle, TrackHandle, NullHandle, and Locator classes.
The design discussion uses the following simplification (rules)
to shorten the presentation.
- Merging of interface and abstract implementation into one
class. Experienced developers factor the code of an important
abstraction into at least two parts: an interface that represents
the domain concept and an abstract implementation that captures
most of the common implementation aspects of the abstraction.
The abstract implementation is reused by concrete subclasses
[Rie97d, Rie97e].
For our design discussions, these code factoring patterns
are unimportant. We therefore merge interface and abstract implementation
into a single class. A prime example is the JHotDraw interface
Figure and its abstract implementation class AbstractFigure;
both become a single class Figure in our design discussion. Other
examples are Tool and AbstractTool, and Handle and AbstractHandle.
- Subsuming a large set of similar classes under a much smaller
set of representative classes. Frequently, an abstraction has
a large set of similar subclasses that vary only in minor aspects.
Putting all these minor variations as classes into a class model
clutters up its visual presentation, but does not add to the
discussion. Therefore, we use a small set of placeholder classes
to represent the larger set of classes.
The first example is the use of three classes, DecoratorFigure,
CompositeFigure, and ConnectionFigure, to represent the set of
all Figure subclasses. A similar example is the use of CreationTool,
SelectionTool, and HandleTracker to represent the set of all
Tool subclasses. A related but different example is the use of
a (fake) placeholder class TrackHandle to represent the different
Handle classes figures use to represent their handles.
These are the same rules that Kent Beck and Erich Gamma applied
in their tutorial on JHotDraw (at least implicitly, as can be
derived by comparing the source code with the tutorial figures).
8.2.2 The Figure classes
This first part of the JHotDraw framework design discussion
describes the Figure class hierarchy. Figure is a central abstraction
of the drawing editor framework. It represents a graphical figure
that users can work with (arrange them to form the drawing). The
discussion comprises the classes Figure, CompositeFigure, DecoratorFigure,
ConnectionFigure, Connector, Handle, and Drawing. It does not
cover all aspects of these classes, but only those relevant from
the perspective of the Figure class hierarchy.
8.2.2.1 Original documentation
Figure 8-2 shows the part of the Figure class hierarchy, as
it can be reengineered from the code. The figure uses plain UML,
and therefore presents the structure of the class model only.
Unnamed associations between classes are associations that are
not bound to a field (=Java instance variable) of one of the involved
classes. They are derived from the abstract state defined in interfaces.
-
-
- Figure 8-2: Structure of the class model of part of the JHotDraw
Figure class hierarchy.
The classes in Figure 8-2 have the following definition (as
taken from the source code, and edited and adapted for the case
study):
- Figure. "A figure knows its display box and can draw
itself. A figure can be composed of several figures. A figure
has a set of handles to manipulate its shape or attributes. A
figure has one or more connectors that define how to locate a
connection point. A figure can have an open ended set of attributes.
A string identifies an attribute. [...]"
- CompositeFigure. "A composite figure is a figure that
is composed of several figures. It does not define any layout
behavior. It is up to subclasses to arrange the contained figures.
[...] A composite figure lets you treat a composition of figures
like a single figure."
- DecoratorFigure. "A decorator figure is used to decorate
other figures with decorations like borders. DecoratorFigure
forwards all the method invocations to its contained figure.
Subclasses can selectively override these methods to extend and
filter behavior. [...] DecoratorFigure is based on the Decorator
pattern."
- ConnectionFigure. "A connection figure connects connector
objects provided by figures. A connection figure knows its start
and end connector. It uses the connectors to locate its connection
points. A connection figure can have multiple segments. It provides
operations to split and join segments. [...] The Strategy pattern
is used to encapsulate the algorithm to locate a connection point.
ConnectionFigure is the Context and Connector is the Strategy
participant. [...] The Observer pattern is used to track changes
of connected figures. A connection figure registers itself as
an observer of the source and target figure."
- Connector. "A connector knows how to locate a connection
point on a figure. A connector knows its owning figure and can
determine either the start or the endpoint of a given connection
figure. A connector has a display box that describes the area
of a figure it is responsible for. A connector can be visible
but it does not have to be. [...] A connector is a Strategy used
to determine the connections points. [...] Connectors are created
by Figure's factory method connectorAt()."
- Handle. "A handle is used to change a figure by direct
manipulation. A figure may have one or more handles. A handle
knows its owning figure, provides its location on the figure,
and helps track changes. [...] A handle adapts the operations
to manipulate a figure to a common interface."
- FigureChangeListener. "A FigureChangeListener object
is a listener interested in figure changes." (Listener interfaces
are a common Java pattern. A Listener interface represents the
callback interface for Observer (= Listener) objects of a given
type of subject, here Figure objects).
- Drawing. "A drawing is a container for figures. A drawing
sends out DrawingChanged events to DrawingChangeListener objects
whenever a part of the drawing's area was invalidated. [...]
The Observer pattern is used to decouple a drawing from its views
and to enable multiple views."
The JHotDraw tutorial provides further information about the
collaborative behavior of instances of these classes. It uses
design patterns to illustrate it. Figure 8-3 shows the abbreviated
and annotated design, as taken from the tutorial.
In this figure, each class is associated with a set of light-blue
annotations that name the participant class of a design pattern
as defined in the design patterns book [GHJV95]. We have added
a few annotations over the original diagrams from the tutorial
to make Client and other participants explicit that seem important
but were missing.
-
-
- Figure 8-3: Use of design patterns in the Figure class hierarchy.
Figure 8-3 shows the use of the Observer, Adapter, Composite,
Decorator, and Strategy design pattern. All of them where mentioned
in the class definitions or could be derived from it.
8.2.2.2 Role model documentation
The design patterns mentioned in the class definitions above
already illustrate some of the collaborative behavior of instances
of these classes. Next to this information, the class definitions
point to the use of the following patterns (which were omitted
from the pattern-annotated class model above):
- Property List. A figure provides a generic set of properties,
accessible using strings as their names.
- Factory Method. A figure creates connector and handle objects
on demand.
- Observer. A connection figure observes its start and end
connection point.
- Manager. A drawing manages several figures as its elements.
Reading the code suggests further role models:
- Domain functionality. All classes provide domain functionality
not captured by any pattern.
These pattern instantiations and non-pattern role models are
displayed in Figure 8-4. This figure shows the full class model
behind the discussed design.
-
-
- Figure 8-4: Role-model-enhanced class model of Figure class
hierarchy.
The following paragraphs describe the role models from the
class model of Figure 8-4. The first part describes all role models
that directly relate clients with the Figure class.
- The Figure role model lets a Client make use of a Figure
object. The Figure class provides the Figure role type, and the
Drawing and Handle classes provide the Client role type.
- The FigureAttribute role model lets a client get and set
any kind of attribute object to a figure object. It is an instance
of the Property List pattern. The Client gets or sets Attribute
objects to the Provider object. The Figure class provides the
Provider role type. The Object class provides the no-operation
Attribute role type. Client is a free role type.
- The FigureObserver role model lets Observer objects (Java
Listeners) observe any figure Subject object. It is an instance
of the Observer pattern. The Figure class provides the Subject
role type and the classes ConnectionFigure, CompositeFigure,
DecoratorFigure, and Drawing provide the free Observer role type.
The second part describes all role models that relate the Figure
class with its subclasses.
- The FigureDecorator role model lets a client decorate any
figure with another figure. It is an instance of the Decorator
pattern. A Client object sets the Core object a decorating Decorator
object. The Figure class provides the Core role type and the
DecoratorFigure class provides the Decorator role type. Client
is a free role type.
- The CompositeFigure role model lets a Client make use of
a Composite figure object. The CompositeFigure class provides
the Composite role type. Client is a free role type.
- The FigureHierarchy role model lets a Client configure a
composite Parent figure with Child figure objects. It is an instance
of the Composite pattern. The Figure class provides the Child
role type and the CompositeFigure class provides the Parent role
type. Client is a free role type.
- The ConnectionFigure role model lets a Client make use of
a Connection figure object. The ConnectionFigure class provides
the Connection role type. Client is a free role type.
- The Connector role model lets a Client make use of Connector
objects. The Connector class provides the Connector role type.
Client is a free role type.
- The ConnectorCreation (ConnCreation in Figure 8-4) role model
lets a client request connector objects from a figure object.
It is an instance of the Factory Method pattern. The Client object
requests a new Product object from the Creator object. The Figure
class provides the Creator role type and the Connector class
provides the Product role type. Client is a free role type.
- The ConnectorStrategy (ConnStrategy in Figure 8-4) role model
lets a client configure a connection figure with connector objects.
It is an instance of the Strategy pattern. The Client configures
the Context object with Strategy objects. The Context delegates
the computation of a connection point to a Strategy. The ConnectionFigure
class provides the Context role type and the Connector class
provides the Strategy role type. Client is a free role type.
The third part describes how the Drawing class relates to the
Figure class.
- The Drawing role model lets a Client make use of a Drawing
object. The Drawing class provides the Drawing role type. Client
is a free role type.
- The DrawingObserver role model lets observer objects register
at and be notified about changes by a drawing. It is an instance
of the Observer pattern. The Observer object observes the Subject
object. The DrawingView class provides the Observer role type
and the Drawing class provides the Subject role type.
- The FigureContainer role model lets clients add, find, and
remove figure objects from a drawing object. It is an instance
of the Manager pattern. The Container manages its Elements and
provides them to Clients. The Drawing class provides the Manager
role type and the Figure class provides the opaque Element role
type, and the classes DrawingView and SelectionTool provide the
Client role type.
Finally, this last part describes how the Handle class relates
to the Figure class.
- The Handle role model lets a Client make use of a Handle
object. The Handle class provides the Handle role type. Client
is a free role type.
- The HandleCreation role model lets a client request handle
objects from a figure object. It is an instance of the Factory
Method pattern. The Figure class provides the Creator role type
and the Handle class provides the Product role type. Client is
a free role type.
- The FigureAdapter role model lets a handle object adapt its
owning figure object to client requests. It is an instance of
the Adapter pattern. The Handle class provides the Handle role
type, Figure class provides the Adaptee role type, and the HandleTracker
class provides the Client role type.
Of these 16 role models, 10 are pattern instances.
8.2.3 The Drawing and DrawingView classes
This second part of the JHotDraw framework design discussion
describes the Drawing, DrawingView, and related classes. A drawing
is a set of figures, displayed in a drawing view. Users manipulate
the figures through the drawing view. The discusses the classes
Figure, Drawing, DrawingView, Tool, Painter, PointConstrainer,
and DrawingEditor.
8.2.3.1 Original documentation
Figure 8-5 shows the Drawing, DrawingView, and related classes.
The figure uses plain UML and therefore presents the structure
of the class model only. Again, unnamed associations and aggregations
have been derived from the abstract state definitions in the interfaces
of the involved classes.
-
-
- Figure 8-5: Structure of the class model of part of the Drawing
and DrawingView classes.
The classes in Figure 8-5 have the following definition (as
taken from the source code, and edited and adapted for the case
study):
- Figure, FigureChangeListener, Drawing. See definition in
Section 8.2.2.
- DrawingChangeListener. "A DrawingChangeListener is a
listener of Drawing instance changes."
- DrawingView. "A drawing view renders a drawing and listens
to its changes. It receives user input and delegates it to the
current tool. [...] A drawing view observes a drawing for changes
via the DrawingChangeListener interface. [...] A drawing view
plays the Context role in the State pattern. Tool is the State.
[...] DrawingView is the Context in the Strategy pattern with
regard to the Painter. [...] DrawingView is also the Context
for the PointConstrainer."
- Painter. "A painter encapsulates an algorithm to render
something in a drawing view. A drawing view plays the Context
role of the Strategy pattern, and the painter plays the Strategy
role."
- PointConstrainer. "A point constrainer constrains a
point. It can be used to implement different kinds of grids.
[...] DrawingView is the Context, and PointConstrainer is the
Strategy participant."
- DrawingEditor. "A drawing editor coordinates the different
objects that participate in a drawing editor. [...] A drawing
editor manages possibly several drawing views. DrawingEditor
is a Mediator that decouples several participants." (Participant
classes are Tool and DrawingView).
- Tool. "A tool defines a mode of a drawing view. All
input events targeted to the drawing view are forwarded to its
current tool. When it is done with an interaction, a tool informs
its editor by calling the editor's toolDone() method. A tool
is created once and reused. It is initialized/deinitialized with
activate()/deactivate(). [...] Tool plays the role of the State.
It encapsulates all state specific behavior. A drawing view plays
the Context role of the State pattern.
The JHotDraw tutorial provides further information. Figure
8-6 shows the abbreviated and annotated design, as taken from
the tutorial.
-
-
- Figure 8-6: Use of design patterns for the Drawing and DrawingView
classes.
Figure 8-6 shows the use of the Observer (repeatedly), Strategy
(repeatedly), State, and Factory Method design patterns. Again,
most of it could be derived straight from the class documentation.
Please note that we added the Factory Method Client participant
(to class DrawingEditor) over the original documentation. Most
patterns are about collaborative behavior of objects, and the
Client is one important participant in such a collaboration.
8.2.3.2 Role model documentation
Next to pattern information from the tutorial, the class definitions
point to the use of the following patterns:
- Mediator. A drawing editor acts as a mediator for the drawing
view, drawing, and tool colleagues.
Reading the code suggests further role models:
- Domain functionality. All classes provide domain functionality
not captured by any pattern.
Figure 8-7 shows these pattern instances as role models together
with the non-pattern role models of the domain functionality.
This figure shows the full class model behind the discussed part
of the design. All role models that have been introduced in the
previous subsection are visually grayed-out in the figure and
not discussed further.
-
-
- Figure 8-7: Class model of Drawing and DrawingView classes
enhanced with role models.
The following paragraphs describe the role models from Figure
8-7 that have not been defined before (for the others, see Section
8.2.2).
The following first part describes all role models that focus
on the DrawingView class.
- The DrawingView role model lets a Client make use of a drawing
View object. The DrawingView class provides the View role type.
Client is a free role type.
- The Painter role model lets a drawing view delegate the view
update to a painter strategy, which calls back on the view to
draw it. It is an instance of the Strategy pattern. The Painter
class provides the Strategy role type, the DrawingView class
provides the Context role type, and the DrawingEditor provides
the Client role type.
- The PointConstrainer role model lets a drawing view delegate
the computation of a grid to a constrainer object. It is an instance
of the Strategy pattern. The PointConstrainer class provides
the Strategy role type and the DrawingView class provides the
Context role type. Client is a free role type.
The second part describes all role models that focus on the
DrawingEditor class.
- The EditorMediator role model decouples drawing views from
the drawing and the current tool through an intermediate editor
object. It is an instance of the Mediator pattern. The Editor
is the mediator, and DrawingView and Tool objects are the colleagues.
The DrawingEditor class provides the Editor role type, the DrawingView
class provides the View role type, and the Tool class provides
the Tool role type.
- The ToolAccess role model lets a client request the current
tool from the editor. It is an instance of the Manager pattern.
A Client object asks the Manager object to return a specific
Element object, here the currently active Tool object. The Tool
class provides the opaque Element role type, the DrawingEditor
class provides the Manager role type, and the DrawingView class
provides the Client role type.
- The ToolCreation role model lets the drawing editor create
a tool object. It is an instance of the Factory Method pattern.
The DrawingEditor class provides the Client and Creator role
type and the Tool class provides the Product role type.
The third part describes all role models that focus on the
Tool class.
- The Tool role model lets a client make use of a tool object.
The Tool class provides the Tool role type and the DrawingEditor
class provides the Client role type.
- The ToolState role model lets a client delegate detailed
input handling to a tool object. It is an instance of the State
pattern. The client object acts as the Context to the tool object
that acts as the State. The Tool class provides the State role
type and the DrawingView and SelectionTool classes provide the
Context role type.
Of these 8 role models, 6 are pattern instances, cast as role
models.
8.2.4 The DrawingEditor classes
This third part of the JHotDraw framework discussion describes
the DrawingEditor and related classes. The drawing editor is the
coordinating object that creates all command and tool objects.
Drawing views manipulate figures of a drawing using these tool
objects. During this direct manipulation, tools make use of handles.
8.2.4.1 Original documentation
Figure 8-8 shows the class model of the DrawingEditor class
and its related Tool and Handle classes. The figure uses plain
UML, and therefore presents only the structure of the class model.
Again, unnamed associations and aggregations have been derived
from the abstract state definitions in the interfaces of the involved
classes.
-
-
- Figure 8-8: Structure of the class model of part of the DrawingEditor
classes.
The classes in Figure 8-8 have the following definition (as
taken from the source code, and edited and adapted for the case
study):
- Figure, Drawing, DrawingView, DrawingEditor, Tool. See definitions
in Section 8.2.2 and 8.2.3.
- CreationTool. "A creation tool is a tool that is used
to create new figures. The figure to be created is specified
by a prototype. [...] A creation tool creates new figures by
cloning a prototype."
- HandleTracker. "A handle tracker is a tool that implements
interactions with the handles of a figure."
- SelectionTool. "A selection tool is a tool that is used
to select and manipulate figures. A selection tool is in one
of three states: background selection, figure selection, or handle
manipulation. Different child tools handle the different states.
[...] SelectionTool is the Context and a child tool is the State
participant of the State pattern. A selection tool delegates
state specific behavior to its current child tool."
- Handle. "A handle is used to change a figure by direct
manipulation. A handle knows its owning figure and provides methods
to locate the handle on the figure and to track changes. [...]
A handle adapts the operations to manipulate a figure to the
common Handle interface. [...]"
- TrackHandle. TrackHandle is a (fake) placeholder class that
represents any of the NorthHandle, NorthEastHandle, EastHandle,
etc. classes. These classes represent the traditional handles
of a rectangular figure.
- NullHandle. "A null handle is a handle that does not
change the owned figure. Its only purpose is to show that a figure
is selected. [...] A null handle lets you treat handles that
do not do anything in the same way as other handles."
- LocatorHandle. "A locator handle is a handle that delegates
the location requests to a locator object."
- Locator. "A locator is used to locate a position on
a figure. [...] Locators encapsulate a strategy to locate a handle
on a figure."
The design patterns mentioned in the class definitions above
illustrate some of the collaborative behavior of instances of
these classes. The JHotDraw tutorial provides further information.
Figure 8-9 shows the abbreviated and annotated design, as taken
from the tutorial.
-
-
- Figure 8-9: Use of design patterns for the DrawingEditor
classes.
As mentioned earlier, to simplify the discussion, the Handle
and LocatorHandle classes are merged to form a single Handle class.
With it, Handle becomes the Strategy context for Locator objects.
This design now shows the use of the Observer (repeatedly),
Strategy (repeatedly), State (repeatedly), Adapter, Prototype,
Factory Method, and Null Object pattern.
8.2.4.2 Role model documentation
Next to pattern information from the tutorial, the class definitions
point to the use of the following patterns:
- Factory Method. A figure creates handles with locator objects.
A selection tool creates handle trackers.
Reading the code suggests further role models:
- Domain functionality. All classes provide dedicated domain
functionality not captured by any pattern.
Figure 8-10 shows these pattern instantiations as role models
and adds non-pattern role models that represent the domain functionality.
The figure shows the full class model behind the classes selected
for this part of the discussion.
-
-
- Figure 8-10: Role-model-enhanced class model of DrawingEditor
classes.
The following paragraphs describe the role models of Figure
8-10 that have not yet been defined and discussed (for the other
role models, see Section 8.2.2 and 8.2.3).
- The TrackerCreation role model lets a selection tool create
a new handle tracker object for its own use. It is an instance
of the Factory Method pattern. The SelectionTool class provides
the Client and Creator role types and the HandleTracker class
provides the Product role type.
- The FigurePrototype role model lets a Client create a new
object by cloning the Prototype. It is an instance of the Prototype
pattern. The Figure class provides the Prototype role type and
the CreationTool class provides the Client role type.
- The LocatorCreation role model lets a figure object create
locator objects. It is an instance of the Factory Method pattern.
The Figure class provides both the Client and the Creator role
type and the Locator class provides the Product role type.
- The LocatorStrategy role model lets a locator handle delegate
the computation of its position on the drawing area to a locator
object. It is an instance of the Strategy pattern. The LocatorHandle
class provides the Context role type and the Locator class provides
the Strategy role type.
All of these 4 remaining role models are pattern instances.
8.3 Experiences and evaluation
This final subsection presents some statistics from the case
study. It examines the observations made during carrying out the
case study. These observations are related to the complexity of
classes, the complexity of object collaboration, the clarity of
expected client behavior, and the reuse of design experience.
8.3.1 Statistics of the JHotDraw framework design
The JHotDraw framework provides us with the data shown in Table
8-1.
Number of classes |
20 |
Number of role models |
28 |
Number of pattern instances |
20 |
Number of role types assigned to classes |
66 |
Ratio of role types per class |
3.3 |
Standard deviation of role types per class |
3.02 |
Ratio of role models per class |
1.4 |
Ratio of pattern instances per role model |
0.71 |
Table 8-1: Raw data and computed figures from the JHotDraw
framework.
These figures need to be put into context. The case study describes
a large part of the interface architecture of the JHotDraw framework.
It focuses on the key classes and omits less important implementation
classes. If these less important classes were added, the role
type/class and the pattern instances/role model ratios would decline.
Less important classes typically add less than the average number
of role types per class. Also, less important classes primarily
add role models that are not pattern instances, because they represent
a simple client/service relationship between a client and the
domain functionality of the class.
The pattern instance/role model ration is particularly high,
because JHotDraw is a very mature framework in which all design
aspects have been worked out thoroughly. By following Kent Beck
and Erich Gamma in choosing specifically those classes presented
in this case study, we automatically focussed on design aspects
that could be cast in pattern form.
8.3.2 Observations from the case study
During the definition of the role model interpretation of the
JHotDraw framework design, I made the following observations:
- The JHotDraw documentation infrequently speaks of roles.
Also, the way design aspects are presented is frequently close
to how we speak about role models. However, there is no explicit
mentioning of role models. There are only roles mentioned as
part of the class documentation. Also, the original documentation
uses the terms role and responsibility synonymously.
- Almost all of the design patterns map easily on role models.
The notable exception is the use of the Null Object pattern,
which is purely class implementation oriented. Also, understanding
the class-based version of a pattern proved to be useful (despite
role models) to understand the class hierarchies.
- Role modeling was easy to apply and did not contradict the
original documentation in any way. Rather, it enhanced the existing
information. It also recast the information in a way that unified
the original set of heterogeneous documentation (patterns, code
comments, source code) in a common form.
- It was necessary to read the source code to determine some
of the role models. The role models that were not present in
the original documentation manifested themselves with little
if any operations in a role type (for example, LocatorCreation).
Yet, these role models represent important design aspects.
- Design patterns are an important part of the documentation,
but they do not capture all the collaborative behavior of objects.
Object collaboration tasks that cannot be described as pattern
instances are missed by a design patterns approach.
- The original documentation did not define well which classes
were to act as clients of some other classes and which were not
to act as clients. There was seldom a mentioning of which classes
were supposed to act as clients of a particular feature of a
class.
Based on these general observations, the following subsections
conclude that role modeling is a more uniform and more complete
way of describing a design than is the set of techniques employed
by the original documentation. The following subsections review
these observations in the light of the problems of managing class
complexity, of managing object collaboration complexity, and of
ensuring clarity of use-client requirements. Also, the reuse of
experience through design patterns in JHotDraw is discussed.
8.3.3 Comparison of documentation techniques
Both the original JHotDraw documentation and the role modeling
documentation are not a complete documentation. Rather they are
just one part of a possible more complete documentation. However,
each documentation is based on a specific set of techniques.
The JHotDraw documentation, as already pointed out, uses the
following techniques:
- JavaDoc class documentation. Each relevant class is documented
in the code. The text of the documentation describes the purpose
of the class and how its instances collaborate with other objects
from other classes. A class sometimes also names patterns it
is involved in.
- Pattern annotations. A traditional class model is used to
show the structural relationships between objects and classes.
The classes are annotated with participant names of patterns.
Each participant identifies (through its pattern) some structural
and behavioral aspect of the annotated class.
Role modeling employs two techniques for documenting a design.
- Class as composition of role types. A class is described
as the composition of a set of role types. (The specific documentation
presented here omits a precise specification of this composition
and only suggests it through the class definition itself.)
- Class model with role models. Class relationships are described
by role models. The role models provide a uniform way of defining
object collaboration. They both encompass design pattern applications
and non-pattern based collaborative behavior.
The case study has not documented the classes and role models
in detail. However, it has covered enough ground to compare the
two different documentation approaches.
The following subsections compare the two sets of documentation
with each other.
8.3.3.1 Documentation of classes
The Figure class serves as an example for the comparison. There
is no significant difference between Figure and any other key
class, so we can generalize from Figure to the other classes.
The Figure class defines the following roles, as derived from
the source code, JavaDoc comments, and the tutorial.
- A figure knows how to display itself (primary domain functionality).
- A figure can be composed from several figures (Composite
pattern).
- A figure is manipulated through a set of handles (Factory
Method and Adapter pattern).
- A figure provides connectors that define connection points
(Factory Method).
- A figure can have an open-ended set of attributes (Property
List pattern).
- A figure sends out events to registered observers (Observer
pattern).
- A figure can be cloned to create a new figure (Prototype
pattern).
- A figure may act as the core to a decorating figure (Decorator
pattern).
- A figure provides locator objects for locator handles (Factory
Method).
- A figure acts as an element of a drawing (Manager pattern).
The last two responsibilities could only be found by reading
the source code. They were not present in the JavaDoc comments
or the tutorial. One possible reason is that they were simply
forgotten. Another one is that a responsibility without operations
(like a figure acting as a drawing element) is easily overlooked.
A third possible reason is that the last example is not a pattern
from [GHJV95].
Yet it is important to capture all the responsibilities. In
the role-model-based documentation, all of these responsibilities
are described using role types from specific role models.
These role types are: Figure.Figure, FigureHierarchy.Child,
HandleCreation.Creator and FigureAdapter.Adaptee, ConnCreation.Creator,
FigureAttribute.Provider, FigureObserver.Subject, FigurePrototype.Prototype,
FigureDecorator.Core, LocatorCreation.Client and LocatorCreation.Creator,
and FigureContainer.Element.
From this discussion, we can conclude the following:
- The role type documentation is more complete than the original
documentation, because role modeling lets us capture all the
responsibilities of a class. This includes behavioral responsibilities
that do not come with operations of their own and that are not
participants of pattern instances.
- The role type documentation is more homogeneous than the
original documentation. It uses one concept, role type, rather
than several (role, protocol, responsibility, pattern participant).
Yet, this single uniformly applied concept delivers a more complete
description of a class.
Thus, role modeling gives a more homogeneous and more complete
definition of a class.
8.3.3.2 Documentation of collaboration tasks
We continue with the comparison of collaboration tasks using
the Figure class. Above, we identified several role types of the
Figure class. However, isolated roles do not describe how clients
collaborate with a Figure instance. Yet, we can determine the
object collaborations from the JHotDraw source code and its documentation.
- General clients use the domain functionality of a figure.
- CompositeFigure instances embed further figures (Composite
pattern).
- Handle (subclass) instances are created by a figure (Factory
Method pattern).
- Handle instances adapt a figure for interactive use (Adapter
pattern).
- Connector instances are created by a figure (Factory Method
pattern).
- General clients get and set figure attributes using generic
key/value pairs (Property List pattern).
- FigureChangeListener (implementor) instances receive events
from a figure (Observer pattern).
- CreationTool instances clone a figure prototype for new figures
(Prototype pattern).
- DecoratorFigure (subclass) instances decorate any kind of
figure (Decorator pattern).
- Locator instances are created by a figure (Factory Method
pattern).
- A Drawing instance manages figures as its elements (Manager
pattern).
Some of these collaborations could be derived from the JavaDoc
comments, and some of them could be derived from the pattern annotations
in the tutorial. However, the last two collaborations were not
documented, neither using JavaDoc comments, nor in the tutorial.
One possible reason is again that they were easy to overlook,
because they did not come with operations. Another reason is that
they are not pattern instances and therefore could not be captured
using pattern annotations.
Yet again, these missing collaborations make up an important
part of what should be documented about the Figure class and its
collaborations. In the role-model-based documentation, all of
these collaborations are described using role models.
These role models are: Figure, FigureHierarchy, HandleCreation
and FigureAdapter, ConnCreation, FigureAttribute, FigureObserver,
FigurePrototype, FigureDecorator, FigureContainer, and LocatorCreation.
From this discussion, we can conclude the following:
- The role model documentation is more complete than the original
documentation, because role modeling lets us capture all relevant
collaboration tasks. This includes collaboration tasks that are
not pattern instances and that are easy to overlook.
- The role model documentation is more homogeneous than the
original documentation. It uses one concept, role model, compared
to the concepts of class and pattern annotation. Yet, this single
uniformly applied concept delivers a more complete description
of a class and its collaborations.
Thus, role modeling gives a more homogeneous and more complete
definition of the individual object collaboration tasks of a framework
and hence of its overall object collaboration.
8.3.3.3 Documentation of requirements put upon use-clients
Finally, we consider the overall set of classes. None of the
class documentation makes requirements put upon use-clients explicit.
The client is always assumed to make proper use of the framework
objects. Also, there is no hint towards which classes clients
may use, and which they may not use.
Role modeling in contrast makes all Client role types explicit,
whether they are derived from design pattern instantiations or
not. In addition, by qualifying role types as free, role modeling
lets developers specify which role types are visible to outside
clients and may be used by them.
In the context of JHotDraw, we can therefore conclude that
role modeling lets us specify requirements put upon use clients,
whereas the original techniques do not provide such means.
8.3.4 Complexity of classes
Measured by the size of their role type sets, the most complex
classes of the case study are the Figure, DrawingView, DrawingEditor,
Drawing, and Tool class. These are 5 out of 20 discussed classes.
The Figure class is a complex class that can be described well
and uniformly using role types. The interpretation of the design
using role modeling demonstrates this: it provides all the information
from the source code and the tutorial, and it adds information
that has been missing from the original documentation.
The role-model-based description does not contradict the original
documentation. The contrary is true: both the responsibilities
defined in the class comments and the design pattern participants
annotating the class map directly on role types. The role-model-based
description is an extension of the existing documentation, cast
in a uniform way.
Traditional class-focussed documentation only provides the
structural relationships between classes. The way JHotDraw is
documented strongly suggests that this is insufficient to communicate
its design. The tutorial tries to overcome this shortcoming by
annotating the design with pattern participants. Yet, as the documentation
has shown, role modeling delivers a more complete and more homogeneous
picture of the design than the original documentation does.
The comparison between role modeling and the JHotDraw techniques,
which are already more elaborate than the traditional purely class-focussed
techniques, lets us conclude the following:
We cannot conclude anything regarding the design process, because
JHotDraw was not developed with role modeling in mind (even though
use of the employed techniques suggest to me that the developer
implicitly used role modeling or something very similar to it).
8.3.5 Complexity of object collaboration
Complex classes are one side of the coin, complex object collaborations
the other. Instances of the core classes Figure, Drawing, DrawingView,
DrawingEditor, and Tool collaborate with each other in several
different ways. Understanding how these collaborations work is
vital to understanding the framework design.
The behavior of instances of (subclasses of) Figure in relation
to other objects can be described using role models. In contrast
to the aforementioned set of heterogeneous techniques, role modeling
lets us do this in a uniform and complete way. The role-model-based
presentation of the framework captures all the information provided
by the original developer and adds information that is missing.
Again, the role-model-based documentation does not contradict
the original documentation but rather enhances it. It adds to
it where necessary. Design patterns may uniformly document collaborative
behavior. However, they do not do this completely; they miss out
collaboration tasks that cannot be described as pattern instances.
In the context of JHotDraw, these arguments based on the comparison
of the two sets of documentation, let us conclude the following
on the use of role modeling for complex object collaborations.
- Learning and using complex collaborations. As shown above,
role modeling is a technique that lets us more effectively describe
object collaboration behavior than possible with the techniques
employed in the JHotDraw documentation. It is more effective
than design patterns, because patterns ignore role models not
based on patterns.
More effectively describing object collaboration behavior
means making it easier for developers to learn and use the classes
involved in the collaboration. The need for breaking up the overall
collaboration into pieces is recognized in the original JHotDraw
documentation through the use of design patterns, but is only
carried out fully through the use of role models.
JHotDraw was not designed with role modeling in mind, so we
cannot conclude anything on the design process of the object collaboration
tasks.
8.3.6 Clarity of requirements put upon use-clients
Role modeling makes requirements put upon use-clients explicit,
as far as the method allows. The original documentation does not
address this problem.
In the context of JHotDraw, this lets us conclude:
- Learning requirements put upon use-clients, and using a framework
according to these requirements. Both are eased through role
modeling, because the original techniques do not provide any
support here.
JHotDraw was not designed with role modeling in mind, so we
cannot conclude anything on the process of defining the requirements
put upon use-clients.
8.3.7 Reuse of experience through design patterns
JHotDraw, and hence this case study, shines when it comes to
reuse of experience through design patterns. JHotDraw exhibits
a high "design patterns density", i.e., its design is
based on many pattern instances. However, the JHotDraw pattern
annotations and the role modeling technique have different characteristics.
Annotating classes with participant names from a design pattern
indicates that instances of the class exhibit behavior within
the context of the pattern application according to the definition
of the particular participant. However, there is no 1:1 mapping
between a design pattern as presented in [GHJV95], and a specific
class structure, nor is there a 1:1 mapping between a participant
and a specific type or interface. It is not clear how specific
operations and operation signatures look like, because a pattern
is not the same as its application.
Therefore, annotating classes with pattern participants gives
hints to users about the collaborative behavior of its instances,
but does not precisely specify this behavior. Users will always
have to read the class documentation and the source code to determine
which operations belong to which participant.
Role models, on the other hand, are always a concrete rather
than an abstract design artifact. The involved role types specify
precisely (within the capabilities of the chosen specification
mechanism) the behavior of objects conforming to this type. However,
to get a quick grasp at a role model that is a pattern instance,
users have to map a pattern participant onto a role type. Here,
the role-model-based design patterns catalog [Rie97c] helps significantly,
because it already casts the pattern in role model form.
Therefore, with role modeling users do not have to bridge a
gap between a design pattern and a concrete design artifact. There
is no hurdle of understanding a design pattern first, before they
can understand a design.
However, to reuse their design experience, they must connect
the specific role model at hand with an abstract design pattern.
As I have described earlier [Rie96a], role modeling makes it easier
to represent and apply design patterns, because it adds more flexibility
to allocating role types to classes.
Role modeling has a lower entrance hurdle than the original
JHotDraw documentation technique: it does not require developers
to know a pattern to understand a design aspect. However, to fully
benefit from it, design patterns should be known. Role modeling
then makes it easy to recognize these patterns, because it more
flexibly allows their application in a design.
|