// 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