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

examp9.cpp

This example is to show use of the AbstractFactory and Singleton patterns.

What we are working with is right out of the GoF book, the maze factory example with a couple of twists:

A. We are not creating the Maze game, just a AbstractFactory.

B. The behavior of the MapSite objects are not fully defined. I forced some assertion semantics on some things, but I left it mostly alone.

C. Sometimes something happens when you enter it, others are undefined.

And a couple of notes where the libcorelinux differs from the pattern example in the book:

1. We have included a Singleton type template in the library. It's success depends on the adherence to protocol that you won't instantiate the object the singleton guards. The constructor for the Singleton will guard against multiple instantiations of the same type (Singleton<Foo> aFoo; Singleton<Foo> bFoo; the bFoo will assert).

2. The CoreLinux++ implementation of AbstractFactory relies on a collection [0..n] of AbstractAllocators. This was to preserve the abstraction of the factory down to the problem domain; in this case the Maze example.

3. We defered the binding of Key and collection in AbstractFactory so that the developer will have the ultimate flexibility in their designs.

4. In libcorelinux++ we define a macro CORELINUX_DEFAULT_ALLOCATOR which is used when you just want the new and delete memory management. This increases ease of use, and with the addition of instrumentation in both the Allocator base and AbstractFactory, it is easy to monitor which allocations are called more frequently.

Of course, any suggestions to make it better are welcome. Anyway:

We use the corelinux::Identifier as a base for NameIdentifier, we will use this to bind allocators instead of some numbering scheme. They are also self describing in the example.

We will use the CORELINUX_DEFAULT_ALLOCATOR,

See also:
MazeFactory.cpp

The adventerous are welcome to submit more complex Memory Management scenarios.

/*
  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 <Vector.hpp>
#include <Map.hpp>
#include <Singleton.hpp>

using namespace corelinux;

#include <iostream>
#include <exception>

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

//
// In module function prototypes
//

int   main( void );

void  doWork( MazeFactoryPtr aFactory );

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

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

int main( void )
{

   //
   // Practice gracefull exception management
   //

   cout << endl;

   try
   {
      Singleton<MazeFactory>  aFactory;
      doWork( aFactory.instance() );
   }

   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( MazeFactoryPtr aFactory )
{
   bool  keepWorking(true);

   DoorVector  doors;
   WallVector  walls;
   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 ;
               }
               else
               {
                  cerr << "Room " << aNumber << " already exists!" << endl;
               }
               break;
            }

         //
         // Create a Wall. This is a yawner, but the Room interface allows
         // setting up its four sides with walls or doors.
         //

         case  2:
            {
               walls.push_back( aFactory->createWall() );
               cout << endl;
               cout << "You now have " << walls.size() << " wall" << 
                  ( walls.size() > 1 ? "s." : "." ) << endl;
               cout << endl;
               break;
            }

         //
         // Create a door, we need two (2) valid rooms that the door
         // connects 
         //

         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 << "Wall Creates      : " << walls.size() << endl;
   cout << "Door Creates      : " << doors.size() << endl;
   cout << endl;

   //
   // Clean out doors
   //

   DoorVectorIterator  dItr( doors.begin() );

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

   doors.clear();

   //
   // Clean out walls
   //

   WallVectorIterator  wItr( walls.begin() );

   while( wItr != walls.end() )
   {
      aFactory->destroyWall( (*wItr) );
      ++wItr;
   }

   walls.clear();

   //
   // 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.4 $
   $Date: 2000/08/31 22:47:56 $
   $Locker:  $
*/



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