您的位置:首页 > 其它

实战设计模式系列-AbstractFactory(抽象工厂)

2010-03-28 22:42 645 查看
【需求分析】

假设我们需要写一个迷宫游戏,游戏支持用户自由选择游戏的场景,比如可以选择普通的迷宫,或者是有魔法的迷宫等。但所有的迷宫都有一些共同的元素,包括墙壁、门、房间。

只考虑创造一个普通的迷宫,代码比较简单,如下所示:

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, factory.MakeWall());
r1->SetSide(East,  theDoor);
r1->SetSide(South, factory.MakeWall());
r1->SetSide(West, factory.MakeWall());

r2->SetSide(North, factory.MakeWall());
r2->SetSide(West,  theDoor);
r2->SetSide(South, factory.MakeWall());
r2->SetSide(East, factory.MakeWall());

return aMaze;


为了让迷宫支持更多的差异化,我们把迷宫的属性进行细分,可以发现不同的迷宫间有共同的元素,不同的只是元素的属性,或者说元素的实现方式。因此,我们希望这些共同的元素能够被工厂动态的生产出来,然后加入到迷宫当中,如下所示:

aMaze = factory.MakeMaze();
r1 = factory.MakeRoom(1);
r2 = factory.MakeRoom(2);
theDoor = factory.MakeDoor(r1, r2);

aMaze->AddRoom(r1);
aMaze->AddRoom(r2);

r1->SetSide(North, factory.MakeWall());
r1->SetSide(East,  theDoor);
r1->SetSide(South, factory.MakeWall());
r1->SetSide(West, factory.MakeWall());

r2->SetSide(North, factory.MakeWall());
r2->SetSide(West,  theDoor);
r2->SetSide(South, factory.MakeWall());
r2->SetSide(East, factory.MakeWall());


factory是一个工厂,这个工厂可以是一个生产普通迷宫的工厂,或者是生产魔法迷宫的工厂,他们都能生产出同样的迷宫,而只是样式不同。这样就实现了迷宫的动态创建

【实现过程】

1. 实现迷宫的组件抽象类

抽象这些元素的共同点,都有enter接口,因此可以给这些组件定义一个抽象类MapSite,如下所示:

/*MapSite.h*/

#ifndef _MAPSITE_H
#define _MAPSITE_H

enum TYPE {MAPSITE, ROOM, WALL, DOOR};

class MapSite
{
public:
virtual void Enter() = 0;
~MapSite();
virtual int type() = 0;
};

MapSite::~MapSite()
{
printf("Delete MapSite/n");
}

#endif


2.实现迷宫的组件

现在假设要支持两种迷宫,魔法迷宫和可墙壁可爆炸的迷宫。我们先定义房间。

/*Room.h*/
#ifndef _ROOM_H
#define _ROOM_H
enum Direction {North, South, East, West};

class Room : public MapSite
{
public:
Room();
Room(int roomNo);
~Room();
type();
MapSite* GetSide(Direction) const;
void SetSide(Direction dir, MapSite* pMapSite);
int  GetRoomNo();

virtual void Enter();

protected:
int _roomNumber;

private:
MapSite* _sides[4];

};

Room::Room()
{

}

Room::Room(int roomNo)
{
_roomNumber = roomNo;
printf("Create Room NO.%d/n", roomNo);
}

Room::~Room()
{
printf("Delete Room/n");
for (int i = 0; i < 4; i++)
{
if (_sides[i]->type() != DOOR) // TUDO
{
delete _sides[i];
_sides[i] = NULL;
}
}
}

Room::type()
{
return ROOM;
}

void Room::SetSide(Direction dir, MapSite* pMapSite)
{
_sides[dir] = pMapSite;
switch(dir)
{
case East:
printf("Set Room NO.%d East Side/n", GetRoomNo());
break;
case West:
printf("Set Room NO.%d West Side/n", GetRoomNo());
break;
case North:
printf("Set Room NO.%d North Side/n", GetRoomNo());
break;
case South:
printf("Set Room NO.%d East South/n", GetRoomNo());
break;
default:
break;
}
}

int Room::GetRoomNo()
{
return _roomNumber;
}
void Room::Enter()
{
printf("Enter Room/n");
}

class EnchantedRoom : public Room
{
public:
EnchantedRoom(int roomNo)
{
_roomNumber = roomNo;
printf("Create EnchantedRoom NO.%d/n", roomNo);
}
};

class BoomedRoom : public Room
{
public:
BoomedRoom(int roomNo)
{
_roomNumber = roomNo;
printf("Create BoomedRoom NO.%d/n", roomNo);
}
};
#endif


类似的实现墙壁和门。

/*Wall.h*/
#ifndef _WALL_H
#define _WALL_H

class Wall : public MapSite
{
public:
Wall();
~Wall();
type();
virtual void Enter();
};

Wall::Wall()
{
printf("Create Wall/n");
}

Wall::~Wall()
{
printf("Delete Wall/n");
}

Wall::type()
{
return WALL;
}

void Wall::Enter()
{
printf("Enter Wall/n");
}

class EnchantedWall : public Wall
{
public:
EnchantedWall()
{
printf("Create EnchantedWall/n");
}
};

class BoomedWall : public Wall
{
public:
BoomedWall()
{
printf("Create BoomedWall/n");
}
};
#endif


/*Door.h*/

#ifndef _DOOR_H
#define _DOOR_H

#include "Room.h"

class Door : public MapSite
{
public:
Door(Room* r1 = 0, Room * r2 = 0);
~Door();
type();
virtual void Enter();
Room* OtherSideFrom(Room *);

private:
Room* _room1;
Room* _room2;
bool  _isOpen;
};

Door::Door(Room* r1, Room * r2):_room1(r1), _room2(r2)
{
printf("Create Door between Room %d and %d/n", r1->GetRoomNo(), r2->GetRoomNo());
}

Door::~Door()
{
printf("Delete Door/n");
}

Door::type()
{
return DOOR;
}

void Door::Enter()
{
printf("Enter Door/n");
}

#endif


3.实现工厂

工厂必须能生产门,墙和房间,因此这些应该是基类的抽象接口。

/*MazeFacory.h*/
#ifndef _MAZEFACTORY_H
#define _MAZEFACTORY_H

#include "Maze.h"
#include "Room.h"
#include "Wall.h"
#include "Door.h"

class MazeFactory // Abstract class
{
public:
MazeFactory()
{
printf("Create MazeFactory/n");
}

virtual Maze* MakeMaze() const
{
return new Maze;
}

virtual Wall* MakeWall() const = 0;

virtual Room* MakeRoom(int n) const = 0;

virtual Door* MakeDoor(Room* r1, Room* r2) const
{
return new Door(r1, r2);
}

};

class EnchantedMazeFactory : public MazeFactory
{
public:
EnchantedMazeFactory()
{
printf("Create MazeFactory");
}

virtual Room* MakeRoom(int n) const
{
return new EnchantedRoom(n);
}

virtual Wall* MakeWall() const
{
return new EnchantedWall();
}
};

class BoomedMazeFactory : public MazeFactory
{
public:
BoomedMazeFactory()
{
printf("Create MazeFactory");
}

virtual Room* MakeRoom(int n) const
{
return new BoomedRoom(n);
}

virtual Wall* MakeWall() const
{
return new BoomedWall();
}
};
#endif


4.实现迷宫类

/*MazeGame.h*/
#ifndef _MAZEGAME_H
#define _MAZEGAME_H

#include "Maze.h"
#include "Room.h"
#include "Wall.h"
#include "Door.h"
#include "MazeFactory.h"

class MazeGame
{
public:
MazeGame();
~MazeGame();
Maze* CreateMaze(MazeFactory& factory);
private:
Maze* aMaze;
Room* r1;
Room* r2;
Door* theDoor;
};

MazeGame::MazeGame()
{
printf("Create MazeGame/n");
}

MazeGame::~MazeGame()
{
delete aMaze;
delete theDoor;
printf("Delete MazeGame/n");
}

Maze* MazeGame::CreateMaze(MazeFactory& factory)
{
aMaze = factory.MakeMaze();
r1 = factory.MakeRoom(1);
r2 = factory.MakeRoom(2);
theDoor = factory.MakeDoor(r1, r2);

aMaze->AddRoom(r1);
aMaze->AddRoom(r2);

r1->SetSide(North, factory.MakeWall());
r1->SetSide(East,  theDoor);
r1->SetSide(South, factory.MakeWall());
r1->SetSide(West, factory.MakeWall());

r2->SetSide(North, factory.MakeWall());
r2->SetSide(West,  theDoor);
r2->SetSide(South, factory.MakeWall());
r2->SetSide(East, factory.MakeWall());

return aMaze;
}

#endif


5.如何使用

#include <stdio.h>
#include <stdlib.h>

#include "MapSite.h"
#include "Room.h"
#include "Wall.h"
#include "Door.h"
#include "Maze.h"
#include "MazeGame.h"

int main(void)
{
MazeGame *pMazeGame = new MazeGame;
int tag;
printf("EnchantedMaze:1/nBoomedMaze:2/n");
printf("Enter your choice:/n");
scanf("%d", &tag);
EnchantedMazeFactory pEnchangtedFactory;
BoomedMazeFactory    pBoomedMazeFactory;
switch(tag)
{
case 1:
pMazeGame->CreateMaze(pEnchangtedFactory);
case 2:
pMazeGame->CreateMaze(pBoomedMazeFactory);
}

delete pMazeGame;
return 0;
}


【总结】

抽象工厂在抽象工厂类中定义接口,子类中实现父类的方法,不同的配置方式就有多个子类去实现,而客户只使用父类中提供的接口,通过传参数的方式在客户类中决定用那个具体的工厂去实例化对象。
下图是本文中举例的图示,图中MazeFactory作为父类限定了接口,可以是抽象类,也可是具体类,如是具体类,则可以定义一个最基本的功能接口,并可以在Client类MazeGame中初实例化。
客户类MazeGame接收一个MazeFactory引用参数来实例化一个产品,通过传入具体类的参数在运行时刻决定应该实例化那一个类。
Room和Wall作为组件使用来构建具体的工厂类。
这个模式的缺点在于难以支持新种类的产品,每增加一个新的功能就要修改抽象工厂类的接口。
抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: