Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Examples  

examp10.cpp

This example is to show use of the Flyweight pattern.

What we do here is utilize a flyweight because of the following assumptions:

Assumption: Rooms have sides with cardinality of [4] Assumption: The side can be either a door or a wall Assumption: The room has at least one (1) door

Unless it is an extreme maze, there is a high probability that there are more walls in a room than doors. By using the Flyweight pattern we can reduce our instance requirements by ( rooms * (sides==walls) ) - 1, for example:

20 rooms with an average of 3 walls each saves 59 wall instances!

The memory savings are the walls * sizeof( wall ) in general and the cycle savings are the new and deletes needed to instantiate and destroy each wall.

Then there is the probable reduction in the locality of reference faults when actually doing something with a wall. But that is beyond the scope of this example.

Anyway, in this example we play with pre-building a room with three (3) walls each. In addition, we utilize the Room interface of setting a side to the room instance.

Refer to ex9 for some of the first order class implementations. You will notice that we reuse almost everything from ex9 except for the Wall (in theory), the MazeFactory for creating the Wall, and the changes in the examp10.cpp source.

A more realistic implementation would have a MazeFactory that is configurable to register allocators so we don't need to expose the application to whether it is using a Flyweight or a true Class instance. Stay tuned, with Builder, Factory Method and a few other patterns we will achieve this and more.

/*
  CoreLinux++ 
  Copyright (C) 2000 CoreLinux Consortium
  
   The CoreLinux++ Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   The CoreLinux++ Library Library is distributed in the hope that it will 
   be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with the GNU C Library; see the file COPYING.LIB.  If not,
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  
*/   

#include <Common.hpp>
#include <MazeFactory.hpp>
#include <WallFactory.hpp>

#include <Vector.hpp>
#include <Map.hpp>

using namespace corelinux;

#include <iostream>
#include <exception>

CORELINUX_VECTOR(  DoorPtr ,  DoorVector );
CORELINUX_MAP(  RoomNumber,  RoomPtr,  less<RoomNumber> ,  RoomMap );

//
// In module function prototypes
//

int   main( void );

void  doWork( MazeFactoryRef , WallFactoryRef );

//
// Functions that work with Engine types
//

void  handleAssertion( AssertionCref );
void  handleException( ExceptionCref );

int main( void )
{

   //
   // Practice gracefull exception management
   //

   cout << endl;

   try
   {
      MazeFactory aFactory;
      WallFactory aWallFactory;

      doWork( aFactory, aWallFactory );
   }

   catch( AssertionRef aAssert )
   {
      handleAssertion(aAssert);
   }
   catch( ExceptionRef aException )
   {
      handleException(aException);
   }
   catch( std::exception & e )
   {
      cerr  << e.what() << endl;
   }
   catch( ... )
   {
      cerr  << "Unknown exception." << endl;
   }

   return 0;               
}

void  displayMenu( void )
{
   cout  << endl;
   cout  << "\tCreate a Room                    1" << endl;
   cout  << "\tCreate a Wall                    2" << endl;
   cout  << "\tCreate a Room                    3" << endl;
   cout  << "\tQuit the example                 4" << endl;
   cout  << endl;
}

Int   getCommand( void )
{
   displayMenu();

   Int   aOption;

   cout  << "Enter the option number on the right to execute : ";
   cin   >> aOption;

   return aOption;
}

void  doWork( MazeFactoryRef aFactory, WallFactoryRef aWallFactory )
{
   bool  keepWorking(true);

   DoorVector  doors;
   RoomMap     rooms;

   do
   {
      Int   aCommand( getCommand() );

      if( aCommand > 4 || aCommand < 0 )
      {
         cerr << "You can't enter non-numeric options!" << endl;
         aCommand = 4;
      }
      else
      {
         ;  // do nothing
      }

      switch( aCommand )
      {
         //
         // Create a new room and insure that the same
         // doesn't already exist
         //

         case  1:
            {
               RoomNumber  aNumber(0);
               cout << endl;
               cout << "Enter a RoomNumber for the new room : ";
               cin  >> aNumber;
               if( rooms.find(aNumber) == rooms.end() )
               {
                  RoomPtr  aRoom( aFactory.createRoom(aNumber) );
                  rooms[aNumber] = aRoom ;

                  //
                  // To bring this into reality, we will look
                  // to the best case scenario and auto create
                  // three (3) walls per room, all doors lead
                  // to the east!
                  //

                  aRoom->setSide( NORTH, aWallFactory.createType() );
                  aRoom->setSide( SOUTH, aWallFactory.createType() );
                  aRoom->setSide( WEST,  aWallFactory.createType() );
               }
               else
               {
                  cerr << "Room " << aNumber << " already exists!" << endl;
               }
               break;
            }

         //
         // Create a Wall. This is where we saved our job by
         // getting the maze to scale.
         //

         case  2:
            {
               IGNORE_RETURN aWallFactory.createType();
               cout << endl;

               cout << "You now have " << 
                  aWallFactory.getAllocateCount() << " wall" << 
                  ( aWallFactory.getAllocateCount() > 1 ? "s." : "." ) << 
                  endl;

               cout << endl;
               break;
            }

         //
         // Create a door, we need two (2) valid rooms that the door
         // connects. But there is a bug here. Get involved, fix 
         // the sample, become part of the open development process.
         //

         case  3:
            {
               RoomNumber  aFirstNumber(0);
               RoomNumber  aSecondNumber(0);

               cout << endl;
               cout << "Enter the first room the door connects : ";
               cin  >> aFirstNumber;
               cout << endl;
               cout << "Enter the second room the door connects : ";
               cin  >> aSecondNumber;

               if( rooms.find(aFirstNumber) == rooms.end() ||
                   rooms.find(aSecondNumber) == rooms.end() )
               {
                  cerr << "You need to enter valid room numbers." << endl;
               }
               else
               {
                  doors.push_back
                     (
                        aFactory.createDoor
                           (
                              (*rooms.find(aFirstNumber)).second,
                              (*rooms.find(aSecondNumber)).second
                           )
                     );

                  cout << "You now have " << doors.size() << " door" << 
                     ( doors.size() > 1 ? "s." : "." ) << endl;

               }
               break;
            }

         //
         // Add a parent to an object
         //

         case  4:
            keepWorking=false;
            break;

         default:
            ;  //do nothing
            break;
      }
   } while( keepWorking == true );

   //
   // Now we can display info and clean up
   //

   cout << endl;
   cout << "Pre-cleanup Factory Statistics" << endl;
   cout << "==============================" << endl;
   cout << "Total Creates     : " << aFactory.getTotalAllocates() << endl;
   cout << "Total Destroys    : " << aFactory.getTotalDeallocates() << endl;
   cout << "Room Creates      : " << rooms.size() << endl;
   cout << "Door Creates      : " << doors.size() << endl;
   cout << "Wall Creates      : " << aWallFactory.getAllocateCount() << endl;

   cout << "\t For a general memory saving of : " << 
      sizeof( Wall ) * aWallFactory.getAllocateCount() << " bytes!" << endl;

   cout << endl;

   //
   // Clean out doors
   //

   DoorVectorIterator  dItr( doors.begin() );

   while( dItr != doors.end() )
   {
      aFactory.destroyDoor( (*dItr ) );
      ++dItr;
   }

   doors.clear();

   //
   // Clean out walls, but wait!!! We don't have to
   //

   //
   // Clean out rooms
   //

   RoomMapIterator   rItr( rooms.begin() );

   while( rItr != rooms.end() )
   {
      aFactory.destroyRoom( (*rItr).second );
      ++rItr;
   }

   rooms.clear();

   //
   // Final statistics
   //

   cout << endl;
   cout << "Post-cleanup Factory Statistics" << endl;
   cout << "===============================" << endl;
   cout << "Total Creates     : " << aFactory.getTotalAllocates() << endl;
   cout << "Total Destroys    : " << aFactory.getTotalDeallocates() << endl;
   cout << endl;

}

//
// Peform default (just show it)
//

void  handleAssertion( AssertionCref aAssert )
{
   cerr << aAssert.getFile() << ":" << aAssert.getLine() << ":" << 
      "Assertion: ";

   if( aAssert.getType() == Assertion::NEVERGETHERE )
   {
      cerr << "NEVER_GET_HERE";
   }
   else
   {
      if( aAssert.getType() == Assertion::REQUIRE )
      {
         cerr  << "REQUIRE";
      }
      else if( aAssert.getType() == Assertion::ENSURE )
      {
         cerr  << "ENSURE";
      }
      else if( aAssert.getType() == Assertion::CHECK )
      {
         cerr  << "CHECK";
      }
      else 
      {
         cerr  << "ASSERT";
      }
      cerr << "( " << aAssert.getWhy() << " )";
   }

   cerr << endl;
}

void  handleException( ExceptionCref aExcp )
{
   cerr << aExcp.getFile() << ":" << aExcp.getLine() << ":" <<
      "Exception: " << aExcp.getWhy() << endl;
}

/*
   Common rcs information do not modify
   $Author: prudhomm $
   $Revision: 1.3 $
   $Date: 2000/08/31 22:51:01 $
   $Locker:  $
*/



This is the CoreLinux++ reference manual
Provided by The CoreLinux Consortium