设计形式中迷宫的实现,用于学习创建型模式

设计模式中迷宫的实现,用于学习创建型模式

    设计模式一书相信不少人看过。其中创建型模式一节通过一个创建迷宫的例子阐述了工厂模式、抽象工厂模式等创建型模式。对于初学者而言,书中讲解并未实现具体代码,对于几种设计模式的优势不能深刻的体会。出于学习的目的我实现了这个迷宫,并且尽量保持原书中的类结构,用于体会创建型模式的优点。代码并不难,详见注释。本源码中仅实现了抽象工厂模式,其他模式详见设计模式一书。注意启动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;
}