An illustration of this approach would be Motif widgets that have been re-engineered as light-weight gadgets. Whereas widgets are "intelligent" enough to stand on their own; gadgets exist in a dependent relationship with their parent layout manager widget. Each layout manager provides context-dependent event handling, real estate management, and resource services to its flyweight gadgets, and each gadget is only responsible for context-independent state and behavior.
Ant, Locust, and Cockroach
classes can be "light-weight" because their instance-specific state
has been de-encapsulated, or externalized, and must be supplied by
the client.
| Before | After | |
|---|---|---|
// Trying to use objects at very low levels of
// granularity is nice, but the overhead may be
// prohibitive. Flyweight suggests removing the
// non-shareable state from the class, and having
// the client supply it when methods are called.
// This places more responsibility on the client,
// but, considerably fewer instances of the Fly-
// weight class are now created. Sharing of these
// instances is facilitated by introducing a Fac-
// tory class that maintains a "cache" of existing
// Flyweights.
//
// In this example, the "X" state is considered
// shareable (within each row anyways), and the
// "Y" state has been externalized (it is sup-
// plied by the client when report() is called).
class Gazillion {
public:
Gazillion() {
m_value_one = s_num / Y;
m_value_two = s_num % Y;
++s_num;
}
void report() {
cout << m_value_one << m_value_two << ' ';
}
static int X, Y;
private:
int m_value_one;
int m_value_two;
static int s_num;
};
int Gazillion::X = 6, Gazillion::Y = 10,
Gazillion::s_num = 0;
int main( void ) {
Gazillion matrix[Gazillion::X][Gazillion::Y];
for (int i=0; i < Gazillion::X; ++i) {
for (int j=0; j < Gazillion::Y; ++j)
matrix[i][j].report();
cout << '\n';
} }
// 00 01 02 03 04 05 06 07 08 09
// 10 11 12 13 14 15 16 17 18 19
// 20 21 22 23 24 25 26 27 28 29
// 30 31 32 33 34 35 36 37 38 39
// 40 41 42 43 44 45 46 47 48 49
// 50 51 52 53 54 55 56 57 58 59
|
class Gazillion {
public:
Gazillion( int value_one ) {
m_value_one = value_one;
cout << "ctor: "<< m_value_one << '\n';
}
~Gazillion() {
cout << m_value_one << ' ';
}
void report( int value_two ) {
cout << m_value_one << value_two << ' ';
}
private:
int m_value_one;
};
class Factory {
public:
static Gazillion* get_fly( int in ) {
if ( ! s_pool[in])
s_pool[in] = new Gazillion( in );
return s_pool[in];
}
static void clean_up() {
cout << "dtors: ";
for (int i=0; i < X; ++i)
if (s_pool[i])
delete s_pool[i];
cout << '\n';
}
static int X, Y;
private:
static Gazillion* s_pool[];
};
int Factory::X = 6, Factory::Y = 10;
Gazillion* Factory::s_pool[] = { 0,0,0,0,0,0 };
int main( void ) {
for (int i=0; i < Factory::X; ++i) {
for (int j=0; j < Factory::Y; ++j)
Factory::get_fly(i)->report(j);
cout << '\n';
}
Factory::clean_up();
}
// ctor: 0
// 00 01 02 03 04 05 06 07 08 09
// ctor: 1
// 10 11 12 13 14 15 16 17 18 19
// ctor: 2
// 20 21 22 23 24 25 26 27 28 29
// ctor: 3
// 30 31 32 33 34 35 36 37 38 39
// ctor: 4
// 40 41 42 43 44 45 46 47 48 49
// ctor: 5
// 50 51 52 53 54 55 56 57 58 59
// dtors: 0 1 2 3 4 5
|
Flyweight is often combined with Composite to implement shared leaf nodes. [GoF, p206]
Terminal symbols within Interpreter's abstract syntax tree can be shared with Flyweight. [GoF. p255]
Flyweight explains when and how State objects can be shared. [GoF, p313]