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,
/* 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: $ */