v Today: More on patterns
Ø A little history
Ø Notation
Ø A study of a specific pattern
v A little background on design patterns
(Gang of Four and others)
Ø In 1977, Christopher Alexander and
colleagues (Center for Environmental Structure) wrote a collection of three
books architecture, building, and planning
§
More on Alexander is available on the web
Ø One of them, A Pattern Language, is based
on the notion that “in designing their environments, people always rely on
certain `languages,’ which, like the languages we speak, allow them to
articulate and communicate an infinite variety of designs within a formal
system which gives them coherence.”
Ø Indeed, the book discusses over two hundred
patterns that are intended to give concrete guidance in designing towns,
buildings, and construction
Ø Example: Activity Pockets (#124)
§
“The life of
a public square forms naturally around the edge. If the edge fails, then the space never becomes lively.
§
“Therefore:
Surround public gathering places with pockets of activity---small, partly
enclosed areas at the edges, which jut forward into the open space between the
paths, and contain activities which make it natural for people to pause and get
involved.”
Ø One can push the analogies to Alexander’s
work too far; but it is taken very seriously by many members of the computing
research community; Alexander gave a keynote at OOPSLA, for instance
v Notation
Ø The patterns in the GoF (Gang of
Four---Gamma, Helm, Johnson, Vlissides) book (Amazon Sales Rank 257) are
described in an "OMT-based notation"
Ø OMT was one of several popular notations
for describing aspects of object-oriented models/designs (Booch, Coad/Yourdon,
and others were also common)
Ø A number of the OO analysis/design bigwigs
(in particular, Booch, Rumbaugh, and Jacobson) combined at Rational to design
UML, the "Unified Modeling Language"
Ø UML, with significant input from many many
companies and individuals, is becoming adopted as an industry-standard notation
§
Amazon today
lists 31 books with "UML" in the title, including ones that rank 124,
248, 571, 894, and 1693
Ø While I don't want to go into full detail
(UML is quite large and complex), I think it's important to be able to read the
basics of UML
§
The current
documentation of UML is almost 700 pages!
Ø Someone in Finland has converted all the GoF pattern structures into UML
Ø Here's the flyweight pattern description in
UML (comes at the end of the file/page)
§
The boxes represent
classes (except for the box hanging off FlyweightFactory by a dotted line),
with the bold-faced name indicating the class that is being represented
·
<stereotype>
is a UML detail (you won't find it in the OMT notation in the GoF book) that
basically says, hey, this is a completely new class, don't treat it like
anything else that has structural similarity (the Ada type system lets you do
this, too, as do some other programming languages)
§
The elements
in the subbox underneath the class name indicate the operations provided (UML
allows for attributes to be defined, too, but this example shows only
operations)
·
The
"+" indicates that the operations are public (with "-" and
"#" representing private and protected, respectively)
§
The arrows of
various sorts represent relationships between the classes
·
The arrow between
FlyweightFactory and Flyweight indicates that Flyweight is part-of; the
"1" at the right side of this arrow indicates that there is precisely
one Flyweight instance in instantiations of FlyweightFactory
·
The arrows
from ConcreteFlyweight and from UnsharedConcreteFlyweight to Flyweight are
inheritance relations (they each inherit from Flyweight)
·
The three
lines from Client represent that Client owns references to instances of these
three classes
§
The box
associated with FlyweightFactory shows pseudocode that captures the basics of
the exported operation
Ø More information on each participant
§
Flyweight
·
Declares an
interface through which flyweights can receive and act on extrinsic state
¨ So, if you were managing (lots of)
character objects, you might prefer to keep font and style information
extrinsic (external to) the objects, since there are in general far fewer fonts
and styles used than characters
·
FlyweightFactory
¨ Creates and manages flyweight objects
¨ Ensures that flyweights are shared properly
¨ When a client requests a flyweight, the
FlyweightFactory object supplies an existing instance or creates one, if none
exists
·
ConcreteFlyweight
¨ Implements the Flyweight interface (thus
the inheritance in the diagram) and adds storage for the intrinsic state, if
any
Ø Intrinsic state is that which is
independent of the context in which the ConcreteFlyweight object is used (e.g.,
a specific character, like "a")
¨ Must be sharable
·
UnsharedConcreteFlyweight
¨ Allows for Flyweight instances that are not
shared
¨ Can have shared ConcreteFlyweight children,
too
¨ An example is where you have columns of
text, each containing rows of characters
Ø The columns and the rows might be
UnsharedConcreteFlyweights, while the characters themselves might be
ConcreteFlyweights
·
Client
¨ Maintains reference to flyweight(s)
¨ Computes or stores extrinsic state of
flyweights
Ø Code from the GoF for a use of Flyweight
#include "defs.H"
class Window;
class GlyphContext;
class Font {
public:
Font(char*);
};
class BTree;
class Glyph {
public:
virtual ~Glyph();
virtual void
Draw(Window*, GlyphContext&);
virtual void
SetFont(Font*, GlyphContext&);
virtual Font*
GetFont(GlyphContext&);
virtual void
First(GlyphContext&);
virtual void
Next(GlyphContext&);
virtual bool
IsDone(GlyphContext&);
virtual Glyph*
Current(GlyphContext&);
virtual void
Insert(Glyph*, GlyphContext&);
virtual void
Remove(GlyphContext&);
protected:
Glyph();
};
class Character : public Glyph {
public:
Character(char);
virtual void
Draw(Window*, GlyphContext&);
private:
char _charcode;
};
class GlyphContext {
public:
GlyphContext();
virtual
~GlyphContext();
virtual void
Next(int step = 1);
virtual void
Insert(int quantity = 1);
virtual Font*
GetFont();
virtual void
SetFont(Font*, int span = 1);
private:
int _index;
BTree* _fonts;
};
void dummy () {
GlyphContext gc;
Font* times12 = new Font("Times-Roman-12");
Font* timesItalic12 = new Font("Times-Italic-12");
// ...
gc.SetFont(times12, 6);
gc.Insert(6);
gc.SetFont(timesItalic12, 6);
}
class Row {
};
class Column {
};
const int NCHARCODES = 128;
class GlyphFactory {
public:
GlyphFactory();
virtual
~GlyphFactory();
virtual
Character* CreateCharacter(char);
virtual Row*
CreateRow();
virtual Column*
CreateColumn();
// ...
private:
Character*
_character[NCHARCODES];
};
GlyphFactory::GlyphFactory () {
for (int i = 0; i
< NCHARCODES; ++i) {
_character[i] = 0;
}
}
Character* GlyphFactory::CreateCharacter (char c) {
if
(!_character[c]) {
_character[c]
= new Character(c);
}
return
_character[c];
}
Row* GlyphFactory::CreateRow () {
return new Row;
}
Column* GlyphFactory::CreateColumn () {
return new
Column;
}