考虑一个多风格的界面应用,要求可以切换不同风格类型的组件(窗口,滚动条,按钮等)
风格/组件 | pm风格 | motif风格 |
---|---|---|
滚动条 | pmScrollBar | motifScrollBar |
窗口 | pmWindow | MotifWindow |
WidgetFactory: 抽象工厂,用于创建滚动条和窗口。
MotifWidgetFactory: 继承抽象工厂(WidgetFactory),用于给Motif类型创建滚动条和窗口。
他依赖于MotifWindow和MotifScrollBar
PMWidgetFactory: 继承抽象工厂(WidgetFactory),用于给PM类型创建滚动条和窗口。
他依赖于PMWindow和PMScrollBar
Client: 客户端,用来操作软件或者系统
支持多种格式的富文本阅读器(RTF),比如tex文本,ASCII, WIDGET
客户端解析文本时,先选择builder,然后根据文本流不同类型,转换不同成不同的格式
比如:tex格式支持复杂的数学公式,只有texbuilder有这个分支
未完待续
背景:设计一个迷宫,仅考虑迷宫的构成:由一系列房间,墙,门组成。房间知道邻居是谁:房间,墙或者门。门连接两个房间。忽略所有和游戏者相关的操作:移动,显示等。
定义方向:enum Direction {North,South, East, West}
Class MapSite
{
public:
virtual void Enter()=0;
};
class Room : public MapSite {
public :
Room (int roomNo)
MapSite* GetSide (Direction) const;
void SetSide (Direction, Mapsite*);
virtual void Enter()
private:
MapSite* _sides[4] ;
int _roomNumber;
};
class Wall : public MapSite {
public :
Wall();
virtual void Enter( ) ;
};
class Door public Mapsite {
public :
Door (Room* = 0, Room* = 0) ;
virtual void Enter ( )
Room* OtherSideFrom (Room* ) ;
private :
Room* _room1;
Room* _room2;
bool _isOpen ;
} ;
class Maze
{
Public:
Maze ;
void AddRoom (Room* ) ;
Room* RoomNo ( int) const ;
private:
//…
};
//创建迷宫
Maze *MazeGame()
{
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, new Wall);
r1->SetSide(South, theDoor );
r1->SetSide(East, new Wall);
r1->SetSide(West, new Wall);
r2 ->SetSide(North, new Wall);
r2 ->SetSide(South, new Wall);
r2 ->SetSide(East, new Wall);
r2 ->SetSide(West, theDoor );
return aMaze;
}
class MazeFactory (
public
MazeFactory ( ) ;
virtual Maze* MakeMaze() const
{return new Maze; }
virtual Wall* MakeWall() const
{return new Wall; }
virtual Room* MakeRoom(int n) const
{return new Room(n)} )
virtual Door* MakeDoor ( Room* r1, Room* r2) const
{return new Door (rl, r2); }
}
class BombedMazeFactory : public MazeFactory(
public
BombedMazeFactory ( ) ;
virtual Maze* MakeMaze() const
{return new Maze; }
virtual Wall* MakeWall() const
{return new BombedWall; }
virtual Room* MakeRoom(int n) const
{return new BombedRoom(n)} )
virtual Door* MakeDoor ( Room* r1, Room* r2) const
{return new BombedDoor (rl, r2); }
}
Maze *MazeGame:: CreateMaze(MazeFactory & factory)
{
Maze* aMaze =factory. MakeMaze() ;
Room *r1 = factory. MakeRoom(1) ;
Room *r2 =factory. MakeRoom(2) ;
Door theDoor = factory.MakeDoor(r1,r2);
aMaze ->AddRoom(r1);
aMaze ->AddRoom(r2);
r1->SetSide(North, factory.MakeWall() );
r1->SetSide(South, theDoor );
r1->SetSide(East, factory.MakeWall() );
r1->SetSide(West, factory.MakeWall() );
r2 ->SetSide(North, factory.MakeWall() );
r2 ->SetSide(South, factory.MakeWall() );
r2 ->SetSide(East, factory.MakeWall() );
r2 ->SetSide(West, theDoor );
return aMaze;
}
Builder 模式
class MazeBuilder {
public:
virtual void BuildMaze (){}
virtual void BuildRoom (int room) { }
virtual void BuildDoor (int roomFrom. int roomTo ) { }
virtual Maze* GetMaze () { return 0 ; }
protected :
MazeBuiIder();
};
该 接 口 可 以 创 建 : 1 ) 迷 宫 。 2 ) 有 一 个 特 定 房 间 号 的 房 间 。 3 ) 在 有 号 码 的 房 间 之 间 的 门 。
GetMaze 操 作 返 回 这 个 迷 宫 给 客 户 。 MazeBu11der 的 子 类 将 重 定 义 这 些 操 作 , 返 回 它 们 所 创 建
的 迷 宫 。
不定义为纯虚函数,是为了方便派生类只重定义它们感兴趣的接口
用 MazeBuilder 接 口 , 我 们 可 以 改 变 createMaze 成 员 函 数 , 以 生 成 器 作 为 它 的 参 数 。
Maze* MazeGame ::CreateMaze (MazeBuilder & builder)
{
builder.BuildMaze();
builder.BuildRoom(1);
builder.BuildRoom(2);
builder.BuildDoor(1,2) ;
return builder.GetMaze();
}
将 这 个 createMaze 版 本 与 原 来 的 相 比 , 注 意 生 成 器 是 如 何 隐 藏 迷 宫 的 内 部 表 示 的 一 一 一 即 定
义 房 间 、 门 和 墙 壁 的 那 些 类 . 一 一 以 及 这 些 部 件 是 如 何 组 装 成 最 终 的 迷 宫 的 。 有 人 可 能 猜 测 到
有 一 些 类 是 用 来 表 示 房 间 和 门 的 , 但 没 有 迹 象 显 示 哪 个 类 是 用 来 表 示 墻 壁 的 。 这 就 使 得 改 变
一 个 迷 宫 的 表 示 方 式 要 容 易 一 些 , 因 为 所 有 MazeBuiIder 的 客 户 都 不 需 要 被 改 变 。
MazeBuilder自己并不创建迷宫,子 类 做 实 际 工 作:
子 类 StandardMazeBuilder :一 个 创 建 简 单 迷 宫 的 实 现 。 它 将 它 正 在 创 建 的 迷 宫 放 在 变 量 _currentMaze 中 。
class StandardMazeBuiIder : public MazeBuilder
{
Public:
StandardMazeBuilder(){ _currentMaze=0};
virtual void BuildMaze (){ _currentMaze = new Maze;}
virtual void BuildRoom (int room) { }
virtual void BuildDoor (int roomFrom. int roomTo ) { }
virtual Maze* GetMaze () 〔 return _currentMaze; }
Private:
Direction CommonWall( room*, Room*);
Maze* _currentMaze;
}
//创造一个都是墙的房间
void StandardMazeBuilder :: BuildRoom (int n)
{
if (! _currentMaze—>RoomNo (n))
{
Room room =new Room(n);
_currentMaze->AddRoom(room);
room->SetSide (North, new Wall);
room->SetSide(South, new Wall);
room->SetSide(East, new Wall);
room->SetSide(West, nev Wall);
}
}
//建造一扇两个房间之间的门,其中CommonWall找到两个房间相邻的墙壁
Void StandardMazeBuilder::BuildDoor(int n1, int n2)
{
Room* r1 = _currentMaze->RoomNo(n1);
Room* r2 = _currentMaze->RoomNo(n2);
Door *d = new Door(r1,r2);
r1->SetSide(CommonWall(r1,r2) , d);
r1->SetSide(CommonWall(r2,r1) , d);
}
现在客户可以创建迷宫了
Maze* maze;
MazeGame game;
StandardMazeBuiIder builder ;
game. CreateMaze (builder)
Maze= builder.GetMaze();
我 们 本 可 以 将 所 有 的 standardMazeBuiIderN 作 放 在 Maze 中 并 让 每 一 个 Maze 创 建 它 自 身 。
但 将 Maze 变 得 小 一 些 使 得 它 能 更 容 易 被 理 解 和 修 改 , 而 且 standardMazeBuiIder 易 于 从 Maze 中
分 离 。 更 重 要 的 是 , 将 两 者 分 离 使 得 你 可 以 有 多 种 MazeB 回 der , 每 一 种 使 用 不 同 的 房 间 、 墙
壁 和 门 的 类 。
抽象工厂模式强调的是创造不同系列的产品,所以每个产品都有一个抽象类,比如window。而builder模式中,可能无法抽取公共产品抽象类,它更强调产品的构建方式,所以void StandardMazeBuilder :: BuildRoom (int n) 中直接定义了房间是怎么构建的,而在抽象工厂模式这个过程不在MazeFactory 里面而在Maze *MazeGame:: CreateMaze(MazeFactory & factory)函数里,也就是说MazeFactory 只负责创建不同类型的产品,客户负责组装;Builder 则自己组装想要的产品,客户直接拿