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

【需求分析】

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

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

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  

 

[cpp] view plain copy
/*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作为组件使用来构建具体的工厂类。

这个模式的缺点在于难以支持新种类的产品,每增加一个新的功能就要修改抽象工厂类的接口。

抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术之路

WPF MVVM实现TreeView

今天有点时间,做个小例子WPF MVVM 实现TreeView 只是一个思路大家可以自由扩展 文章最后给出了源码下载地址 图1 ?    图2     ? 模...

31590
来自专栏非典型技术宅

iOS实践:一步步实现星级评分1. 创建星星2. 优化3. 灵异事件

18740
来自专栏xingoo, 一个梦想做发明家的程序员

Spark MLlib 之 aggregate和treeAggregate从原理到应用

由于treeAggregate是在aggregate基础上的优化版本,因此先来看看aggregate是什么.

15800
来自专栏算法修养

HDU 1879 继续畅通工程(Kruskra)

继续畅通工程 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 ...

41390
来自专栏逍遥剑客的游戏开发

WOW小地图生成

32530
来自专栏ml

HDUOJ--畅通工程

畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java...

344100
来自专栏算法修养

HDU 1233 还是畅通工程(Kruskal)

还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (J...

26950
来自专栏hbbliyong

使用WPF教你一步一步实现连连看(二)

连连看算法 第一步:我们考虑在同行或者同列的情况: 同行或者同列又分三种情况:   第一:边线,RowNum或者ColNum等于0或者9   第二:两...

41190
来自专栏数据结构与算法

洛谷P2925 [USACO08DEC]干草出售Hay For Sale

题目描述 Farmer John suffered a terrible loss when giant Australian cockroaches ate ...

30440
来自专栏ml

HDUOJ---1233还是畅通工程

还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Ja...

35870

扫码关注云+社区

领取腾讯云代金券