//
Purpose. Flyweight #include <iostream.h>
//
//
Discussion. Trying to use objects const int X = 6;
//
at very low levels of granularity
const int Y = 10;
//
is nice, but the overhead may be
//
prohibitive. Flyweight suggests class Gazillion {
//
removing the non-shareable state
public:
//
from the class, and having the cli-
Gazillion( int in ) {
//
ent supply it when methods are
val1_ = in;
//
called. This places more respon- cout << "ctor:
"<< val1_<<endl; }
//
sibility on the client, but, con-
~Gazillion() {
//
siderably fewer instances of the
cout << val1_ << ' '; }
//
Flyweight class are now created.
void report( int in ) {
//
Sharing of these instances is fa-
cout << val1_ << in << ' '; }
//
cilitated by introducing a Factory
private:
//
class that maintains a "cache" of int val1_;
//
existing Flyweights. };
//
//
In this example, the "X" state is
class Factory {
//
considered shareable (within each
public:
//
row anyways), and the "Y" state has static Gazillion* getFly(int in) {
//
been externalized (it is supplied
if ( ! pool_[in])
//
by the client when report() is
pool_[in] =
//
called). new Gazillion( in );
return pool_[in];
#include
<iostream.h>
}
static void cleanUp() {
const
int X = 6;
cout << "dtors: ";
const
int Y = 10;
for (int i=0; i < X; i++)
if (pool_[i])
class
Gazillion {
delete pool_[i];
public: cout
<< endl;
Gazillion() { }
val1_ = num_ / Y; private:
val2_ = num_ % Y; static Gazillion* pool_[X];
num_++; };
}
void report() { Gazillion*
Factory::pool_[] = {
cout << val1_ << val2_
<< ' ';
0,0,0,0,0,0 };
}
private: void main(
void )
int
val1_; {
int
val2_;
for (int i=0; i < X; i++)
static int num_; {
};
for (int j=0; j < Y; j++)
Factory::getFly(i)->report(j);
int
Gazillion::num_ = 0;
cout << endl;
}
void
main( void )
Factory::cleanUp();
{ }
Gazillion
matrix[X][Y];
for (int i=0; i < X; i++) // ctor: 0
{ // 00 01 02 03 04 05 06 07 08
09
for (int j=0; j < Y; j++) // ctor: 1
matrix[i][j].report(); // 10 11 12 13 14 15 16 17 18 19
cout << endl; // ctor: 2
} // 20 21 22 23 24 25 26 27 28
29
} //
ctor: 3
// 30
31 32 33 34 35 36 37 38 39
//
00 01 02 03 04 05 06 07 08 09 //
ctor: 4
//
10 11 12 13 14 15 16 17 18 19 //
40 41 42 43 44 45 46 47 48 49
//
20 21 22 23 24 25 26 27 28 29 //
ctor: 5
//
30 31 32 33 34 35 36 37 38 39 // 50 51 52 53 54 55 56 57 58 59
//
40 41 42 43 44 45 46 47 48 49 //
dtors: 0 1 2 3 4 5
//
50 51 52 53 54 55 56 57 58 59
//
Purpose. Flyweight design pattern demo.
//
//
Discussion. Flyweight describes how to
share objects, so that their
//
use at fine granularities is not cost prohibitive. A key concept is
//
the distinction between "intrinsic" and "extrinsic"
state. Intrinsic
//
state consists of information that is independent of the flyweight's
//
context - information that is sharable (i.e. each Icon's name, width,
//
and height). It is stored in the
flyweight (i.e. the Icon class).
//
Extrinsic state cannot be shared, it depends on and varies with the
//
flyweight's context (i.e. the x,y position that each Icon instance's
//
upper left corner will be drawn at).
Extrinsic state is stored or
//
computed by the client and is passed to the flyweight when an operation
//
is invoked. Clients should not
instantiate Flyweights directly, they
//
should obtain them exclusively from a FlyweightFactory object to ensure
//
they are shared properly.
#include
<iostream.h>
#include
<string.h>
class
Icon {
public:
Icon( char* fileName ) {
strcpy(
_name, fileName );
if
( ! strcmp(fileName, "go"))
{ _width = 20; _height = 20; }
if
( ! strcmp(fileName, "stop"))
{ _width = 40; _height = 40; }
if
( ! strcmp(fileName, "select")) { _width = 60; _height = 60; }
if
( ! strcmp(fileName, "undo"))
{ _width = 30; _height = 30; } }
const char* getName() { return _name; }
draw( int x, int y ) {
cout
<< " drawing "
<< _name << ": upper left (" << x <<
"," << y
<<
") - lower right (" << x + _width << ","
<< y + _height << ")"
<<
endl; }
private:
char
_name[20];
int
_width;
int
_height;
};
class
FlyweightFactory {
public:
static Icon* getIcon( char* name ) {
for
(int i=0; i < _numIcons; i++)
if
( ! strcmp( name, _icons[i]->getName() ))
return _icons[i];
_icons[_numIcons]
= new Icon( name );
return
_icons[_numIcons++]; }
static void reportTheIcons() {
cout
<< "Active Flyweights: ";
for
(int i=0; i < _numIcons; i++)
cout
<< _icons[i]->getName() << " ";
cout
<< endl; }
private:
enum { MAX_ICONS = 5 };
static int _numIcons;
static Icon* _icons[MAX_ICONS];
};
int FlyweightFactory::_numIcons = 0;
Icon*
FlyweightFactory::_icons[];
class
DialogBox {
public:
DialogBox( int x, int y, int incr ) :
_iconsOriginX(x), _iconsOriginY(y),
_iconsXIncrement(incr)
{ }
virtual void draw() = 0;
protected:
Icon* _icons[3];
int
_iconsOriginX;
int
_iconsOriginY;
int
_iconsXIncrement;
};
class
FileSelection : public DialogBox {
public:
FileSelection( Icon* first, Icon* second,
Icon* third ) :
DialogBox(100,100,100)
{
_icons[0]
= first;
_icons[1]
= second;
_icons[2]
= third; }
void draw() {
cout
<< "drawing FileSelection:" << endl;
for
(int i=0; i < 3; i++)
_icons[i]->draw(
_iconsOriginX + (i * _iconsXIncrement),
_iconsOriginY ); }
};
class
CommitTransaction : public DialogBox {
public:
CommitTransaction( Icon* first, Icon*
second, Icon* third ) :
DialogBox(150,150,150)
{
_icons[0]
= first;
_icons[1]
= second;
_icons[2]
= third; }
void draw() {
cout
<< "drawing CommitTransaction:" << endl;
for
(int i=0; i < 3; i++)
_icons[i]->draw(
_iconsOriginX + (i * _iconsXIncrement),
_iconsOriginY ); }
};
void
main() {
DialogBox* dialogs[2];
dialogs[0] = new FileSelection(
FlyweightFactory::getIcon("go"),
FlyweightFactory::getIcon("stop"),
FlyweightFactory::getIcon("select")
);
dialogs[1] = new CommitTransaction(
FlyweightFactory::getIcon("select"),
FlyweightFactory::getIcon("stop"),
FlyweightFactory::getIcon("undo")
);
for (int i=0; i < 2; i++)
dialogs[i]->draw();
FlyweightFactory::reportTheIcons();
}
//
drawing FileSelection:
// drawing go: upper left (100,100) - lower
right (120,120)
// drawing stop: upper left (200,100) - lower
right (240,140)
// drawing select: upper left (300,100) -
lower right (360,160)
//
drawing CommitTransaction:
// drawing select: upper left (150,150) -
lower right (210,210)
// drawing stop: upper left (300,150) - lower
right (340,190)
// drawing undo: upper left (450,150) - lower
right (480,180)
//
Active Flyweights: go stop select undo