Growing Frameworks in JavaWilliam
C. Wake, William.Wake@acm.org Note:
This is a draft manuscript. I haven't worked on it in several years. (I
got "distracted" by Extreme Programming :)
I'd still welcome any feedback on the ideas it contains.
IntroductionGoals:
·
What
is a framework? ·
Show
how to move from basic code to a framework. ·
Sensitize
reader to opportunities for developing frameworks Hats: ·
end
user ·
framework
user = application developer ·
framework
developer Basics: Definition Source
materials Background
skills The Zoo
Mini-Framework
There’s
a class of games for pre-schoolers, where they can make simple pictures, and
things happen when they click on the pictures. To support such an application,
let’s consider a simple framework for that game.
A. Main area: Animals make
a sound when clicked, and move when dragged. B. Cast: when animal is
clicked, it makes a sound and a new one appears in the main area. C. Chatter: At random,
animals highlight and make a sound until clicked again. D. Erase: The screen is
reset to an empty screen. If
you’re building a program like this once, you probably don’t need a framework.
But suppose you envision a whole line of games: Zoo, Construction Zone, Ocean, etc.
Then a framework can pay off. Hot
Spots This
brings us to the fundamental question when designing a framework: What will change, and what will
stay the same? The
parts that change are hot spots (to use Wolfgang Pree’s term [ref]).
They represent points of flexibility and control. For
many years, it’s been a tenet of good programming that code should encapsulate
decisions (see Parnas’ writings [ref]). By making a segment of code hide one
decision, we acquire flexibility when changing that decision. In
our small example, we have a few things that should change: ·
the
screen title ·
the
list of “animals” ·
their
sounds The
main screen, the placement of items, and the overall actions will stay the
same. The
Framework We
can imagine a framework to help us create these games. It might be like this: Instructions
for Using the Shape Game Framework You can control: ·
screen
title ·
list
of shapes ·
sound
for each shape Screen
title The
screen title is controlled by the arguments given when the program is run. Shapes Each shape should be an instance of DrawableShape. 1.
Extend DrawableShape to create a new class: 2.
Include
a static initialization that registers your class: static {Main.add(new
MyShape();} 3.
Override
clone() to make a copy of your
object. 4.
Override
draw() to create your picture.
You have access to several important attributes: position, size, and foreground
and background colors. 5.
Override
getSound() to return a Sound
object. Defaults ·
The
title defaults to “Shape Game”. ·
If
you don’t override draw(), it defaults to a smiley face. ·
If
you don’t override getSound(), it defaults to a “boing” sound. ·
If
you don’t register any items, the default provides a single smiley face. No Assembly
Required
Notice
what happens if you don’t add anything to the framework: the defaults kick in,
to yield a minimal version “Shape Game” with a smiley face that goes boing. This
is a powerful technique (often ignored). It lets the application developer move
from a system that works (though not how they want) to a system that works
(more like they want). Instead of having to leap across the river, they can
work a stepping stone at a time. The
alternative is a “pile of parts”: assemble them correctly and you get
“something”. What
Can We Tell?
The
framework has some things that change, and some that stay the same. Change: Title, Pictures, Sound Same: Screen arrangement,
Behavior The
framework defines a way to make the changes happen.
One
classic feature that this framework shows is that the framework controls the
flow of control - our objects do not. For example, when are draw() or
getSound() called? We don’t know - the framework decides.
A
further issue is how objects are designed. Do we have to understand the code of
the framework to use it? If so, it is “white box.” If we can use it without
understanding the existing code, it is more “black box.” (This is a matter of
degree.) The
best approach is to make the most flexible features be black box. In our
example, setting the sound requires no knowledge of the internals of the
framework. On the other hand, changing when the sound happens might require
subclassing framework classes and making substantial changes. Carried
to the extreme, the black box case will require no code changes at all. This is
how JavaBeans work: many parameters can be set, and beans can be connected
together, without any code. As
features become more standardized, and their patterns of use become better
understood, we can find ways to control them with even less code. For example,
our framework could use this approach: “For each menu item, create a
picture file named x.gif, and a sound x.au. Put them in the ‘menu’ directory. The menu items will appear in alphabetical order by filename.” In
this case, the user wouldn’t need a programmer at all to add new shapes and
sounds. How
do we Achieve Frameworks? We’ll
address a concrete example of converting some existing code into a framework.
We’ll look at rules and design approaches that enable that. [tbd
etc] What is a framework?
Often,
when we develop software, we find ourselves saying “I’ve done that before.” How
many times have you written logging or persistence code, a series of tools that
manipulate the same data structure, or code to handle the same protocol you dealt
with last month? If you’re a web developer, how many times have you written
code to process a form and generate a web page? By
separating the parts common to many applications from the parts specific to
particular applications, we can give ourselves a head start in developing the
next version of an application. “A framework is an application
or partial application…” - Ralph Johnson Subclasses: The
Simplest Frameworks
The
simplest implementation of a framework is something in every inheritance-based
object-oriented programming language: a subclass. The parent class provides the
implementation, and says “if you want to do something different, override this
method.” In
Java, the Applet class provides an example of this: Applet by itself creates an
empty panel, but you can override the paint() method to create your
own screen. Abstract Classes
The
next simplest manifestation of this is in the notion of an abstract class. This
idea is also present in many object-oriented programming languages: an abstract
class is one in which some methods may be implemented, but others are left up
to the subclass. In
UML, it looks like this: an AbstractClass (notice the class name is italicized)
may have some concrete methods, as well as some abstract methods (whose names
are also italicized). The subclass provides an implementation of the abstract
method. (As it is a concrete implementation, its name is no longer italicized.) [TBD] Rose picture AbstractClass
ß
ConcreteClass Moving on Up
Clearly,
two-class “frameworks” can only go so far. Frameworks are more interesting when
there’s a cooperating set of classes. Then we get into issues of how to relate
the classes to each other and to the framework user’s classes. The Three Hats
1.
The end user. This
is the person who is using the software that’s been developed. They don’t care
(directly) that it’s been developed using a framework. (They might be happier
if frameworks get them cheaper or more reliable software, but they’d be just as
happy if that were accomplished by magic.) 2.
The framework user = the
application developer. This
is the person using a framework to create an application. They care about how
hard it is to use the framework, and how much it buys them. 3.
The framework developer. This
person cares about what it takes to create the framework, and whether anybody
uses it. Most
of the time, we’ll be explicit about whether “user” means “end user” or
“framework user.” In those cases where we’re not, it should be clear from the
context which term is meant; usually it will be “framework user.”
|
|
Copyright 1994-2006, William C. Wake - William.Wake@acm.org |