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]