I am looking for an actual example of the use of Factory method pattern in C++. Is there any source code example that gives a good illustration.
3 Answers
I like what does Codeproject teaches:
http://www.codeproject.com/KB/architecture/FactoryPattBasics.aspx
class CUIFrameWork { public: // Instead of hard coding we write factory methods which // perform the task of object creation. virtual CDataComponent* MakeDataComp() { return new CDataComponent(); } virtual CUIComponent* MakeUIComp() { return new CUIComponent(); } virtual CToolBarComponent* MakeToolBarComp( UINT nID ) { return new CToolBarComponent( nID ); } CUITemplate* CreateUI() { CDataComponent* pData = MakeDataComp(); CUIComponent* pUI = MakeUIComp(); CToolBarComponent* pTooBar1 = MakeToolBarComp( ID_STANDARD ); CToolBarComponent* pTooBar2 = MakeToolBarComp( ID_CUSTOM ); pTooBar2->AddDropDownButton(); pTooBar2->AddComboBox(); pUI->AddToolBar(pTooBar1); pUI->AddToolBar(pTooBar2); return new CUITemplate( pData, pUI ); } }; 2 Comments
baris.aydinoz
IMHO, It is more a "builder" than a factory method.
struct pa_diddle { virtual ~pa_diddle(); virtual void diddle() = 0; }; struct bo_diddle : pa_diddle { void diddle() { bo(); }}; struct lee_diddle : pa_diddle { void diddle() { lee(); }}; struct diddle_builder { enum name { BO, LEE }; pa_diddle * build_diddle(name n) { switch(n) { case BO: return new bo_diddle(); case LEE: return new lee_diddle(); } } }; Crud, I totally missed that you were looking for Factory Method, not Abstract Factory. That's what I just gave an example of.
Here's Factory Method:
struct some_abstraction { ... }; struct some_class { ... functions and stuff ... struct something_only_some_class_knows_about : some_abstraction {}; some_abstraction* create_whatnot() const { return new something....about; } }; 5 Comments
Frunsi
+1 for being compact & comprehensive ... and for using structs ;)
6502
I think that in this code the key idea is not really emphasized. The problem is that whoever builds the object still must have the visibility of all the possible classes (at least their "enum-code") and so could do the
if himself. Much more idiomatic is IMO if diddle_builder instead iterates over a vector of constructor functions and if class selector is a general string or integer so that I can write code that creates objects of classes that are not known in any form a compile time (e.g. I don't even know at compile time how many possible classes are there).Edward Strange
@6502 - yeah, sure...but you write it :p That's a bit more work than I'm being paid for at the moment.
Viren
I had given lots of thoughts about having the switch-case construct while creating the object. The main drawback of such code ( including the one that I have pasted above) is that one must write code to "find" code. My best efforts to break that construct was by using jump-tables, which is faster than switch-case. I am curious how other programmers deal with it though.
Edward Strange
I don't understand. What do you mean you must write code to find code?
Direct example from GoF: (sorry for verbosity)
/* */ class Product {}; #ifdef Implementation1 class MyProduct : public Product {}; class YourProduct : public Product {}; class TheirProduct : public Product {}; typedef int ProductId; const int MINE = 1; const int YOURS = 2; const int THEIRS = 2; /* */ class Creator { public: virtual Product* Create(ProductId); }; /* */ Product* Creator::Create (ProductId id) { if (id == MINE) return new MyProduct; if (id == YOURS) return new YourProduct; // repeat for remaining products... return 0; } /* */ class MyCreator : public Creator { public: virtual Product* Create(ProductId); }; /* */ Product* MyCreator::Create (ProductId id) { if (id == YOURS) return new MyProduct; if (id == MINE) return new YourProduct; // N.B.: switched YOURS and MINE if (id == THEIRS) return new TheirProduct; return Creator::Create(id); // called if all others fail } /* */ #endif #ifdef Implementation2 /* */ class Creator { public: Product* GetProduct(); protected: virtual Product* CreateProduct(); private: Product* _product; }; /* */ Product* Creator::GetProduct () { if (_product == 0) { _product = CreateProduct(); } return _product; } /* */ #endif #ifdef Implementation3 /* */ class Creator { public: virtual Product* CreateProduct() = 0; }; /* */ template <class TheProduct> class StandardCreator: public Creator { public: virtual Product* CreateProduct(); }; /* */ template <class TheProduct> Product* StandardCreator<TheProduct>::CreateProduct () { return new TheProduct; } /* */ class MyProduct : public Product { public: MyProduct(); // ... }; StandardCreator<MyProduct> myCreator; /* */ #endif /* */ #include "C++/MazeParts.H" /* */ class MazeGame { public: Maze* CreateMaze(); /* */ // factory methods: /* */ virtual Maze* MakeMaze() const { return new Maze; } virtual Room* MakeRoom(int n) const { return new Room(n); } virtual Wall* MakeWall() const { return new Wall; } virtual Door* MakeDoor(Room* r1, Room* r2) const { return new Door(r1, r2); } }; /* */ Maze* MazeGame::CreateMaze () { Maze* aMaze = MakeMaze(); /* */ Room* r1 = MakeRoom(1); Room* r2 = MakeRoom(2); Door* theDoor = MakeDoor(r1, r2); /* */ aMaze->AddRoom(r1); aMaze->AddRoom(r2); /* */ r1->SetSide(North, MakeWall()); r1->SetSide(East, theDoor); r1->SetSide(South, MakeWall()); r1->SetSide(West, MakeWall()); /* */ r2->SetSide(North, MakeWall()); r2->SetSide(East, MakeWall()); r2->SetSide(South, MakeWall()); r2->SetSide(West, theDoor); /* */ return aMaze; } /* */ class BombedMazeGame : public MazeGame { public: BombedMazeGame(); /* */ virtual Wall* MakeWall() const { return new BombedWall; } /* */ virtual Room* MakeRoom(int n) const { return new RoomWithABomb(n); } }; /* */ class EnchantedMazeGame : public MazeGame { public: EnchantedMazeGame(); /* */ virtual Room* MakeRoom(int n) const { return new EnchantedRoom(n, CastSpell()); } /* */ virtual Door* MakeDoor(Room* r1, Room* r2) const { return new DoorNeedingSpell(r1, r2); } protected: Spell* CastSpell() const; }; /* */ =====================================================================
//Mazeparts.h #included file #ifndef MazeParts_H #define MazeParts_H #include "defs.H" enum Direction { North, East, South, West }; #ifndef MapSite_H #define MapSite_H class MapSite { public: virtual void Enter() = 0; }; #endif #ifndef _H #define _H class Room : public MapSite { public: Room(int = 0); Room(const Room&); virtual Room* Clone() const; void InitializeRoomNo(int); MapSite* GetSide(Direction); void SetSide(Direction, MapSite*); virtual void Enter(); private: MapSite* _sides[4]; int _roomNumber; }; #endif #ifndef Wall_H #define Wall_H class Wall : public MapSite { public: Wall(); Wall(const Wall&); virtual Wall* Clone() const; virtual void Enter(); }; #endif #ifndef Door_H #define Door_H class Door : public MapSite { public: Door(Room* = 0, Room* = 0); Door(const Room&); virtual Door* Clone() const; void Initialize(Room*, Room*); virtual void Enter(); Room* OtherSideFrom(Room*); private: Room* _room1; Room* _room2; bool _isOpen; }; #endif #ifndef Maze_H #define Maze_H class Maze { public: Maze(); Maze(const Maze&); Room* RoomNo(int); void AddRoom(Room*); virtual Maze* Clone() const; private: // ... }; #endif #ifndef BombedWall_H #define BombedWall_H class BombedWall : public Wall { public: BombedWall(bool bombed = false); BombedWall(const BombedWall&); virtual Wall* Clone() const; void Intialize(bool); virtual void Enter(); private: bool _bomb; }; #endif #ifndef RoomWithABomb_H #define RoomWithABomb_H class RoomWithABomb: public Room { public: RoomWithABomb(int = 0, bool bombed = false); RoomWithABomb(const RoomWithABomb&); bool HasBomb(); private: bool _bomb; }; #endif #ifndef EnchantedRoom_H #define EnchantedRoom_H class Spell; class EnchantedRoom : public Room { public: EnchantedRoom(int, Spell* = 0); EnchantedRoom(const EnchantedRoom&); bool HasSpell(); Spell PickUpSpell(); private: Spell* _spell; }; #endif #ifndef DoorNeedingSpell_H #define DoorNeedingSpell_H class DoorNeedingSpell : public Door { public: DoorNeedingSpell(Room*, Room*); DoorNeedingSpell(const DoorNeedingSpell&); bool TrySpell(Spell); }; #endif #endif 2 Comments
Tony Delroy
Maybe a link would have been a better idea? God help anyone wading past that to see answers below....
Viren
I did try to open the ftp link online from where I had downloaded that code when I purchased gof book, but that ftp link is no more working. So I copy-pasted it here. Again, apologies for that.