《设计模式》学习笔记(3)——一个学习创建型模式的例子
又有好久没学习了,而且看书也比较散漫,随手翻到哪里就看到哪里,所以写的学习笔记也比较乱。闲话少说,进入正题。
为什么会有这个例子?
由于创建型模式紧密相关,因此将5个创建型模式以同一个例子来研究更容易说明它们的相似点和相异点。
例子:为一个电脑游戏创建一个迷宫。这个迷宫和游戏可能会随着模式的不同而有所区别:有时候仅仅需要找到一个迷宫的出口;而有时候迷宫可能包括一些要解决的问题等等。
由于首先研究创建型模式,因此我们目前只关心迷宫是怎样被创建的,而不用去关心其他的细节。我们将迷宫定义为一系列的房间,每个房间都知道它的邻居:要么是房间,要么是墙,再要么是通往另一个房间的一扇门。
因此这里将会有三个类:Room, Door和Wall,此外我们还应该关心一下方向,因为一个人站在房间里会有四个方向可以移动,那么就会有一个Direction枚举。
另外,我们可能还需要一个地图,地图上会标明已经探索过的一些元素,如Room或者Wall,因此我们给出一个迷宫元素的基类:MapSite,为了方便,我们给它简单定义一个操作Enter,表示你进入了一个迷宫的元素。下面是他们的关系图及一部分代码:(注:代码仅仅是为了说明,本身无任何意义)
由于Wall类比较简单,因此就不再占用篇幅。至此为止我们定义完了迷宫,下一步我们将要在游戏中生成一个迷宫。一个最直接最简单同时也是最常用的方法就是进行硬编码:
这样,我们生成了一个很简单的迷宫,它仅仅由两个房间以及它们之间的一扇门组成。
现在假设我们有一个新游戏,需要重用上面已有的迷宫布局,但是迷宫中的门是有锁的,需要钥匙才可以打开。很显然,上面的硬编码实现将导致CreateMaze很难重用,于是创建型模式便要登场了。
为什么会有这个例子?
由于创建型模式紧密相关,因此将5个创建型模式以同一个例子来研究更容易说明它们的相似点和相异点。
例子:为一个电脑游戏创建一个迷宫。这个迷宫和游戏可能会随着模式的不同而有所区别:有时候仅仅需要找到一个迷宫的出口;而有时候迷宫可能包括一些要解决的问题等等。
由于首先研究创建型模式,因此我们目前只关心迷宫是怎样被创建的,而不用去关心其他的细节。我们将迷宫定义为一系列的房间,每个房间都知道它的邻居:要么是房间,要么是墙,再要么是通往另一个房间的一扇门。
因此这里将会有三个类:Room, Door和Wall,此外我们还应该关心一下方向,因为一个人站在房间里会有四个方向可以移动,那么就会有一个Direction枚举。
namespace My.Reading.DesignPatterns.MazeGame
{
/// <summary>
/// Direction in the maze.
/// </summary>
public enum Direction
{
North,
South,
East,
West
}
}
{
/// <summary>
/// Direction in the maze.
/// </summary>
public enum Direction
{
North,
South,
East,
West
}
}
另外,我们可能还需要一个地图,地图上会标明已经探索过的一些元素,如Room或者Wall,因此我们给出一个迷宫元素的基类:MapSite,为了方便,我们给它简单定义一个操作Enter,表示你进入了一个迷宫的元素。下面是他们的关系图及一部分代码:(注:代码仅仅是为了说明,本身无任何意义)
namespace My.Reading.DesignPatterns.MazeGame
{
/// <summary>
/// Public abstract class for all of the maze's components.
/// </summary>
public abstract class MapSite
{
public MapSite()
{
}
/// <summary>
/// Decide what you are going to.
/// For example: If you are going to a door, one of the two things will happen:
/// 1. if the door is open, you will enter another room;
/// 2. if the door is closed, you will hit the wall.
/// </summary>
public abstract void Enter();
public abstract void ShowSelfInformation();
}
public class Door : MapSite
{
private Room room1;
private Room room2;
private bool isOpen = false;
public Door(Room room1, Room room2)
{
this.room1 = room1;
this.room2 = room2;
}
public Room OtherSideFrom(Room room)
{
throw new NotImplementedException();
}
public override void Enter()
{
if (isOpen)
{
//
}
else
{
//
}
}
public override void ShowSelfInformation()
{
Console.WriteLine("I am the normal door in namespace MazeGame!");
}
public class Room : MapSite
{
private int roomNo;
private MapSite[] sides = new MapSite[4];
public Room(int roomNo)
{
this.roomNo = roomNo;
}
public int RoomNo
{
get
{
return roomNo;
}
}
public MapSite GetSide(Direction direction)
{
switch (direction)
{
case Direction.North:
return sides[0];
case Direction.East:
return sides[1];
case Direction.South:
return sides[2];
case Direction.West:
return sides[3];
default:
return null;
}
}
public void SetSide(Direction direction, MapSite mapSite)
{
switch (direction)
{
case Direction.North:
sides[0] = mapSite;
break;
case Direction.East:
sides[1] = mapSite;
break;
case Direction.South:
sides[2] = mapSite;
break;
case Direction.West:
sides[3] = mapSite;
break;
default:
break;
}
}
public override void Enter()
{
//
}
public override void ShowSelfInformation()
{
Console.WriteLine("I am the normal room in namespace MazeGame!");
}
public class Maze
{
private ArrayList rooms = new ArrayList();
public Maze()
{
}
public int Count
{
get
{
return rooms.Count;
}
}
public void AddRoom(Room room)
{
rooms.Add(room);
}
/// <summary>
/// Get a room from it's number.
/// </summary>
public Room RoomNo(int roomNo)
{
Room room = null;
for (int i = 0; i < rooms.Count; i++)
{
room = rooms[i] as Room;
if (room.RoomNo == roomNo)
{
break;
}
}
return room;
}
}
{
/// <summary>
/// Public abstract class for all of the maze's components.
/// </summary>
public abstract class MapSite
{
public MapSite()
{
}
/// <summary>
/// Decide what you are going to.
/// For example: If you are going to a door, one of the two things will happen:
/// 1. if the door is open, you will enter another room;
/// 2. if the door is closed, you will hit the wall.
/// </summary>
public abstract void Enter();
public abstract void ShowSelfInformation();
}
public class Door : MapSite
{
private Room room1;
private Room room2;
private bool isOpen = false;
public Door(Room room1, Room room2)
{
this.room1 = room1;
this.room2 = room2;
}
public Room OtherSideFrom(Room room)
{
throw new NotImplementedException();
}
public override void Enter()
{
if (isOpen)
{
//
}
else
{
//
}
}
public override void ShowSelfInformation()
{
Console.WriteLine("I am the normal door in namespace MazeGame!");
}
public class Room : MapSite
{
private int roomNo;
private MapSite[] sides = new MapSite[4];
public Room(int roomNo)
{
this.roomNo = roomNo;
}
public int RoomNo
{
get
{
return roomNo;
}
}
public MapSite GetSide(Direction direction)
{
switch (direction)
{
case Direction.North:
return sides[0];
case Direction.East:
return sides[1];
case Direction.South:
return sides[2];
case Direction.West:
return sides[3];
default:
return null;
}
}
public void SetSide(Direction direction, MapSite mapSite)
{
switch (direction)
{
case Direction.North:
sides[0] = mapSite;
break;
case Direction.East:
sides[1] = mapSite;
break;
case Direction.South:
sides[2] = mapSite;
break;
case Direction.West:
sides[3] = mapSite;
break;
default:
break;
}
}
public override void Enter()
{
//
}
public override void ShowSelfInformation()
{
Console.WriteLine("I am the normal room in namespace MazeGame!");
}
public class Maze
{
private ArrayList rooms = new ArrayList();
public Maze()
{
}
public int Count
{
get
{
return rooms.Count;
}
}
public void AddRoom(Room room)
{
rooms.Add(room);
}
/// <summary>
/// Get a room from it's number.
/// </summary>
public Room RoomNo(int roomNo)
{
Room room = null;
for (int i = 0; i < rooms.Count; i++)
{
room = rooms[i] as Room;
if (room.RoomNo == roomNo)
{
break;
}
}
return room;
}
}
由于Wall类比较简单,因此就不再占用篇幅。至此为止我们定义完了迷宫,下一步我们将要在游戏中生成一个迷宫。一个最直接最简单同时也是最常用的方法就是进行硬编码:
namespace My.Reading.DesignPatterns.MazeGame
{
public class MazeGame
{
public MazeGame()
{
}
public Maze 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(Direction.North, new Wall());
r1.SetSide(Direction.East, theDoor);
r1.SetSide(Direction.South, new Wall());
r1.SetSide(Direction.West, new Wall());
r2.SetSide(Direction.North, new Wall());
r2.SetSide(Direction.East, new Wall());
r2.SetSide(Direction.South, new Wall());
r2.SetSide(Direction.West, theDoor);
return aMaze;
}
}
}
{
public class MazeGame
{
public MazeGame()
{
}
public Maze 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(Direction.North, new Wall());
r1.SetSide(Direction.East, theDoor);
r1.SetSide(Direction.South, new Wall());
r1.SetSide(Direction.West, new Wall());
r2.SetSide(Direction.North, new Wall());
r2.SetSide(Direction.East, new Wall());
r2.SetSide(Direction.South, new Wall());
r2.SetSide(Direction.West, theDoor);
return aMaze;
}
}
}
这样,我们生成了一个很简单的迷宫,它仅仅由两个房间以及它们之间的一扇门组成。
现在假设我们有一个新游戏,需要重用上面已有的迷宫布局,但是迷宫中的门是有锁的,需要钥匙才可以打开。很显然,上面的硬编码实现将导致CreateMaze很难重用,于是创建型模式便要登场了。