// Purpose. Flyweight #include // // 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_< } 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 #include 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