工厂方法举例:运用在建立迷宫中
如下代码所示为运用了工厂模式之前和运用了工厂模式之后的情况。可以看出,运用工厂模式之前,这个函数对迷宫的布局进行硬编码,不灵活。
假设想在一个包含施了魔法的迷宫的新游戏中重用一个已有的迷宫布局,而施了魔法的迷宫游戏有新的构件,如DoorNeedingSpell(一扇仅随着一个咒语才能被锁上和打开的门);以及EnchantedRoom(一个可以有不寻常东西的房间,比如魔法钥匙或是咒语),改变CreateMaze以让它用这些新类型的对象创建迷宫呢,最大障碍是对被实例化的类进行硬编码。
创建型模式提供了多种不同方法从实例化它们的代码中除去对这些具体类的显式引用。
enum Direction {North,East,South,West};
class MapSite{
public:
virtual void Enter()=0;
};
class Room:public MapSite{
public:
Room() {}
Room(int aRoomNo) {}
void SetSide(Direction aDir,MapSite *aMapSite) {}
void Enter() {}
};
class Maze{
public:
Maze() {}
Room* RoomNo(int i) {return new Room;}
void AddRoom(Room* aRoom)
{}
};
class Wall:public MapSite{
public:
Wall() {}
void Enter() {}
};
class Door:public MapSite{
public:
Door(const Room *aRoom1,const Room *aRoom2) {}
void Enter() {}
//private:
// Room* _room1;
// Room* _room2;
// bool _isOpen;
};
class MazeGame{
public:
MazeGame() {}
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) {return new Door(r1,r2);}
Maze* CreateMaze(); //硬编码
Maze* CreateMazeByFactoryMethod();//运用工厂模式
};
class BomWall:public Wall{
public:
BomWall() {}
};
class BomRoom:public Room{
public:
BomRoom(int n) {}
};
class BomMazeGame:public MazeGame{
public: //有炸弹的迷宫
BomMazeGame() {}
Room* MakeRoom(int n)const {return new BomRoom(n);}
Wall* MakeWall()const {return new BomWall;}
};
++++++++++++++++++硬编码++++++++++++++++
Maze* MazeGame::CreateMaze(){//硬编码
Maze* aMaze=new Maze;
Room* r1=new Room(1);
Room* r2=new Room(2);
Door* theDoor=new Door(r1,r2);
aMaze->AddRoom(r1);
aMaze->AddRoom(r2);
r1->SetSide(North,new Wall);
r1->SetSide(East,theDoor);
r1->SetSide(South,new Wall);
r1->SetSide(West,new Wall);
r2->SetSide(North,new Wall);
r2->SetSide(East,new Wall);
r2->SetSide(South,new Wall);
r2->SetSide(West,theDoor);
return aMaze;
}
+++++++++++++运用工厂模式+++++++++
Maze* MazeGame::CreateMazeByFactoryMethod(){//运用工厂模式
Maze* aMaze;
Room *r1,*r2;
Door* theDoor;
aMaze=MakeMaze();
r1=MakeRoom(1);
r2=MakeRoom(2);
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,MakeWall());
return aMaze;
}
+++++++++++++++++++++++++++++++++++++++++
void CFDlg::OnHardSoft()
{
Maze* aMaze;
aMaze=new Maze;
//...
}
void CFDlg::Onstandard()
{
Maze* aMaze;
MazeGame* aGame;
aGame=new MazeGame;
aMaze=aGame->CreateMazeByFactoryMethod();
//...
}
void CFDlg::Onbomb()
{ //有炸弹的迷宫
Maze* aMaze;
MazeGame* aGame;
aGame=new BomMazeGame;
aMaze=aGame->CreateMazeByFactoryMethod();
//....
}
由上实现可见,当要增加一个带炸弹的迷宫时,就将MazeGame派生一下。如:
class BombedMazeGame : public MazeGame {
public:
virtual Wall* MakeWall() const
{ return new BombedWall; }
virtual Room* MakeRoom(int n) const
{ return new RoomWithABomb(n); }
};
这样如果用BombedMazeGame的实例来CreateMaze,则生成的迷宫的Wall和Room就是Bombed。
然而,同时,这也面临一个问题,那就是,如果要增加一个带魔法的迷宫,则需要将MazeGame再派生一下,灵活性是增加了,而是类的种类也增加了。