前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >实战设计模式系列-AbstractFactory(抽象工厂)

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

作者头像
王亚昌
发布2018-08-03 15:39:24
2630
发布2018-08-03 15:39:24
举报
文章被收录于专栏:王亚昌的专栏

【需求分析】

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

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

代码语言:javascript
复制
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;  

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

代码语言:javascript
复制
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,如下所示:

代码语言:javascript
复制
/*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.实现迷宫的组件

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

代码语言:javascript
复制
/*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  

    类似的实现墙壁和门。

代码语言:javascript
复制
/*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.实现工厂

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

代码语言:javascript
复制
/*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.实现迷宫类

代码语言:javascript
复制
/*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.如何使用

代码语言:javascript
复制
#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作为组件使用来构建具体的工厂类。

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

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2010年03月28日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档