設計模式一書相信不少人看過。其中創建型模式一節通過一個創建迷宮的例子闡述了工廠模式、抽象工廠模式等創建型模式。對於初學者而言,書中講解並未實現具體代碼,對於幾種設計模式的優勢不能深刻的體會。出於學習的目的我實現了這個迷宮,並且儘量保持原書中的類結構,用於體會創建型模式的優點。代碼並不難,詳見註釋。本源碼中僅實現了抽象工廠模式,其他模式詳見設計模式一書。注意啓動RTTI,下圖爲運行效果。
以下源碼爲不使用創建型模式的實現。
#include <iostream>
#include <Windows.h>
#include <string.h>
enum Direction{North,South,West,East};
class Coor//在數組中的座標
{
public:
Coor(int v=0,int h=0):vertical(v),horizontal(h){}
int vertical;
int horizontal;
};
class MapSite
{
public:
virtual void Enter()=0;
};
class Wall:public MapSite
{
public:
virtual void Enter()
{
std::cout<<"this is a Wall!"<<std::endl;
}
};
class Room:public MapSite
{
public:
Room(Coor r){
m_linenumber=r.horizontal;
m_rownumber=r.vertical;
}
MapSite* GetSide(Direction d) const
{
return m_sides[d];
}
void SetSide(Direction d,MapSite* m)
{
m_sides[d]=m;
}
virtual void Enter()
{
std::cout<<"You entered the room "<<m_rownumber<<","<<m_linenumber<<std::endl;
}
private:
MapSite* m_sides[4];
int m_linenumber;
int m_rownumber;
};
class Door:public MapSite
{
public:
Door(Room* r1= 0,Room* r2= 0,bool b=true)
{
m_room1=r1;
m_room2=r2;
m_isOpen=b;
}
virtual void Enter()
{
if(m_isOpen==true)
std::cout<<"you went through the door."<<std::endl;
else
std::cout<<"the door is closed."<<std::endl;
}
Room* OtherSideFrom(Room* r)
{
if(r==m_room1)
return m_room2;
else
return m_room1;
}
void setIsOpen(bool b)
{
m_isOpen=b;
}
bool getIsOpen()
{
return m_isOpen;
}
private:
Room* m_room1;
Room* m_room2;
bool m_isOpen;
};
class Person//迷宮中的人
{
public:
Coor getPlace(){return m_place;}
void setPlace(Coor place){
m_place=place;
}
private:
Coor m_place;
};
class Maze//迷宮
{
public:
Maze(int height=3,int width=3,Coor Place=Coor(0,0))
{
m_height=height;
m_width=width;
m_rooms=new Room**[height];
memset(m_rooms,0,height*sizeof(Room**));
m_p.setPlace(Place);
}
void addRoom(Room* r,int h,int w)
{
if(w<0||w>=m_width||h<0||h>=m_height)
return ;
else
{
if (m_rooms[h]==NULL)
m_rooms[h]=new Room*[m_width];
m_rooms[h][w]=r;
}
}
Room* getRoom(int h,int w)
{
return m_rooms[h][w];
}
void pGoWest()//向左走
{
MapSite* m=m_rooms[m_p.getPlace().vertical][m_p.getPlace().horizontal]->GetSide(West);
m->Enter();
if(typeid(*m)==typeid(Room))
{
m_p.setPlace(Coor(m_p.getPlace().vertical,m_p.getPlace().horizontal-1));
}
else if(typeid(*m)==typeid(Door))
{
Door* r=dynamic_cast<Door*>(m);
if(r->getIsOpen()==true)
{
Room* ar=r->OtherSideFrom(m_rooms[m_p.getPlace().vertical][m_p.getPlace().horizontal]);
m_p.setPlace(Coor(m_p.getPlace().vertical,m_p.getPlace().horizontal-1));
ar->Enter();
}
}
return ;
}
void pGoEast()//向右走
{
MapSite* m=m_rooms[m_p.getPlace().vertical][m_p.getPlace().horizontal]->GetSide(East);
m->Enter();
if(typeid(*m)==typeid(Room))
{
m_p.setPlace(Coor(m_p.getPlace().vertical,m_p.getPlace().horizontal+1));
}
else if(typeid(*m)==typeid(Door))
{
Door* r=dynamic_cast<Door*>(m);
if(r->getIsOpen()==true)
{
Room* ar=r->OtherSideFrom(m_rooms[m_p.getPlace().vertical][m_p.getPlace().horizontal]);
m_p.setPlace(Coor(m_p.getPlace().vertical,m_p.getPlace().horizontal+1));
ar->Enter();
}
}
return ;
}
void pGoNorth()//向上走
{
MapSite* m=m_rooms[m_p.getPlace().vertical][m_p.getPlace().horizontal]->GetSide(North);
m->Enter();
if(typeid(*m)==typeid(Room))
{
m_p.setPlace(Coor(m_p.getPlace().vertical+1,m_p.getPlace().horizontal));
}
else if(typeid(*m)==typeid(Door))
{
Door* r=dynamic_cast<Door*>(m);
if(r->getIsOpen()==true)
{
Room* ar=r->OtherSideFrom(m_rooms[m_p.getPlace().vertical][m_p.getPlace().horizontal]);
m_p.setPlace(Coor(m_p.getPlace().vertical-1,m_p.getPlace().horizontal));
ar->Enter();
}
}
return ;
}
void pGoSouth()//向下走
{
MapSite* m=m_rooms[m_p.getPlace().vertical][m_p.getPlace().horizontal]->GetSide(South);
m->Enter();
if(typeid(*m)==typeid(Room))
{
m_p.setPlace(Coor(m_p.getPlace().vertical+1,m_p.getPlace().horizontal));
}
else if(typeid(*m)==typeid(Door))
{
Door* r=dynamic_cast<Door*>(m);
if(r->getIsOpen()==true)
{
Room* ar=r->OtherSideFrom(m_rooms[m_p.getPlace().vertical][m_p.getPlace().horizontal]);
m_p.setPlace(Coor(m_p.getPlace().vertical+1,m_p.getPlace().horizontal));
ar->Enter();
}
}
return ;
}
void PrintMaze()//打印當前迷宮狀態
{
HANDLE hconsole;
hconsole=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hconsole,MAKEWORD(7,0));
for(int i=0;i<m_height;i++)
{
for(int j=0;j<m_width;j++)
{
if(m_p.getPlace().vertical==i&&m_p.getPlace().horizontal==j)
{
SetConsoleTextAttribute(hconsole,MAKEWORD(4,0));
printf("%c ",'P');
continue;
}
if(m_rooms[i][j]==NULL)
{
SetConsoleTextAttribute(hconsole,MAKEWORD(7,0));
}
else
SetConsoleTextAttribute(hconsole,MAKEWORD(3,0));
printf("%d ",j);
}
printf("\n");
}
}
private:
int m_height;
int m_width;
Room*** m_rooms;//二位數組,每個元素是一個指向Room的指針。
Person m_p;
};
class MazeGame
{
public:
void CreateMaze();
void startGame();
private:
Maze *m_maze;
};
void MazeGame::startGame()
{
m_maze->PrintMaze();
char c;
while(std::cin.get(c))
{
if(c=='w')
{
m_maze->pGoNorth();
m_maze->PrintMaze();
}
if(c=='s')
{
m_maze->pGoSouth();
m_maze->PrintMaze();
}
if(c=='a')
{
m_maze->pGoWest();
m_maze->PrintMaze();
}
if(c=='d')
{
m_maze->pGoEast();
m_maze->PrintMaze();
}
}
}
void MazeGame::CreateMaze()
{
Maze* aMaze=new Maze(2,5);
Room* r1=new Room(Coor(0,0));
Room* r2=new Room(Coor(0,1));
Room* r3=new Room(Coor(0,2));
Room* r4=new Room(Coor(0,3));
Room* r5=new Room(Coor(0,4));
Room* r6=new Room(Coor(1,0));
Room* r7=new Room(Coor(1,1));
Room* r8=new Room(Coor(1,2));
Room* r9=new Room(Coor(1,3));
Room* r10=new Room(Coor(1,4));
Door* door1=new Door(r1,r2);
Door* door2=new Door(r2,r3);
Door* door3=new Door(r3,r4,false);
Door* door4=new Door(r4,r5);
Door* door10=new Door(r6,r7);
Door* door11=new Door(r7,r8);
Door* door12=new Door(r8,r9);
Door* door13=new Door(r9,r10,false);
Door* door5=new Door(r1,r6,false);
Door* door6=new Door(r2,r7);
Door* door7=new Door(r3,r8,false);
Door* door8=new Door(r4,r9);
Door* door9=new Door(r5,r10);
aMaze->addRoom(r1,0,0);
aMaze->addRoom(r2,0,1);
aMaze->addRoom(r3,0,2);
aMaze->addRoom(r4,0,3);
aMaze->addRoom(r5,0,4);
aMaze->addRoom(r6,1,0);
aMaze->addRoom(r7,1,1);
aMaze->addRoom(r8,1,2);
aMaze->addRoom(r9,1,3);
aMaze->addRoom(r10,1,4);
r1->SetSide(North,new Wall);
r1->SetSide(South,door5);
r1->SetSide(West,new Wall);
r1->SetSide(East,door1);
r2->SetSide(North,new Wall);
r2->SetSide(South,door6);
r2->SetSide(West,door1);
r2->SetSide(East,door2);
r3->SetSide(North,new Wall);
r3->SetSide(South,door7);
r3->SetSide(West,door2);
r3->SetSide(East,door3);
r4->SetSide(North,new Wall);
r4->SetSide(South,door8);
r4->SetSide(West,door3);
r4->SetSide(East,door4);
r5->SetSide(North,new Wall);
r5->SetSide(South,door9);
r5->SetSide(West,door4);
r5->SetSide(East,new Wall);
r6->SetSide(North,door5);
r6->SetSide(South,new Wall);
r6->SetSide(West,new Wall);
r6->SetSide(East,door10);
r7->SetSide(North,door6);
r7->SetSide(South,new Wall);
r7->SetSide(West,door10);
r7->SetSide(East,door11);
r8->SetSide(North,door7);
r8->SetSide(South,new Wall);
r8->SetSide(West,door11);
r8->SetSide(East,door12);
r9->SetSide(North,door8);
r9->SetSide(South,new Wall);
r9->SetSide(West,door12);
r9->SetSide(East,door13);
r10->SetSide(North,door9);
r10->SetSide(South,new Wall);
r10->SetSide(West,door13);
r10->SetSide(East,new Wall);
m_maze=aMaze;
}
int main()
{
std::cout<<"按wsad進行操作,ctrl+z退出。\n";
MazeGame ng;
ng.CreateMaze();
ng.startGame();
return 0;
}
使用創建型模式,僅需要做少量更改:
class MazeFactory
{
public:
MazeFactory(){};
virtual Maze* MakeMaze(int height,int width,Coor coor) const
{
return new Maze(height,width,coor);
}
virtual Wall* MakeWall() const
{
return new Wall;
}
virtual Room* MakeRoom(Coor coor) const
{
return new Room(coor);
}
virtual Door* MakeDoor(Room* r1,Room* r2,bool b) const
{
return new Door(r1,r2,b);
}
};
void MazeGame::CreateMaze(MazeFactory& factory)
{
Maze* aMaze=factory.MakeMaze(2,5,Coor(0,0));
Room* r1=factory.MakeRoom(Coor(0,0));
Room* r2=factory.MakeRoom(Coor(0,1));
Room* r3=factory.MakeRoom(Coor(0,2));
Room* r4=factory.MakeRoom(Coor(0,3));
Room* r5=factory.MakeRoom(Coor(0,4));
Room* r6=factory.MakeRoom(Coor(1,0));
Room* r7=factory.MakeRoom(Coor(1,1));
Room* r8=factory.MakeRoom(Coor(1,2));
Room* r9=factory.MakeRoom(Coor(1,3));
Room* r10=factory.MakeRoom(Coor(1,4));
Door* door1=factory.MakeDoor(r1,r2,true);
Door* door2=factory.MakeDoor(r2,r3,true);
Door* door3=factory.MakeDoor(r3,r4,false);
Door* door4=factory.MakeDoor(r4,r5,true);
Door* door10=factory.MakeDoor(r6,r7,true);
Door* door11=factory.MakeDoor(r7,r8,true);
Door* door12=factory.MakeDoor(r8,r9,true);
Door* door13=factory.MakeDoor(r9,r10,false);
Door* door5=factory.MakeDoor(r1,r6,false);
Door* door6=factory.MakeDoor(r2,r7,true);
Door* door7=factory.MakeDoor(r3,r8,false);
Door* door8=factory.MakeDoor(r4,r9,true);
Door* door9=factory.MakeDoor(r5,r10,true);
aMaze->addRoom(r1,0,0);
aMaze->addRoom(r2,0,1);
aMaze->addRoom(r3,0,2);
aMaze->addRoom(r4,0,3);
aMaze->addRoom(r5,0,4);
aMaze->addRoom(r6,1,0);
aMaze->addRoom(r7,1,1);
aMaze->addRoom(r8,1,2);
aMaze->addRoom(r9,1,3);
aMaze->addRoom(r10,1,4);
r1->SetSide(North,factory.MakeWall());
r1->SetSide(South,door5);
r1->SetSide(West,factory.MakeWall());
r1->SetSide(East,door1);
r2->SetSide(North,factory.MakeWall());
r2->SetSide(South,door6);
r2->SetSide(West,door1);
r2->SetSide(East,door2);
r3->SetSide(North,factory.MakeWall());
r3->SetSide(South,door7);
r3->SetSide(West,door2);
r3->SetSide(East,door3);
r4->SetSide(North,factory.MakeWall());
r4->SetSide(South,door8);
r4->SetSide(West,door3);
r4->SetSide(East,door4);
r5->SetSide(North,factory.MakeWall());
r5->SetSide(South,door9);
r5->SetSide(West,door4);
r5->SetSide(East,factory.MakeWall());
r6->SetSide(North,door5);
r6->SetSide(South,factory.MakeWall());
r6->SetSide(West,factory.MakeWall());
r6->SetSide(East,door10);
r7->SetSide(North,door6);
r7->SetSide(South,factory.MakeWall());
r7->SetSide(West,door10);
r7->SetSide(East,door11);
r8->SetSide(North,door7);
r8->SetSide(South,factory.MakeWall());
r8->SetSide(West,door11);
r8->SetSide(East,door12);
r9->SetSide(North,door8);
r9->SetSide(South,factory.MakeWall());
r9->SetSide(West,door12);
r9->SetSide(East,door13);
r10->SetSide(North,door9);
r10->SetSide(South,factory.MakeWall());
r10->SetSide(West,door13);
r10->SetSide(East,factory.MakeWall());
m_maze=aMaze;
}