您的位置:首页 > 编程语言 > Delphi

《GOF设计模式》—抽象工厂(Abstract Factory)—Delphi源码示例:基于抽象工厂的迷宫

2014-08-03 17:48 537 查看


示例:基于抽象工厂的迷宫

实现:
如果TMaze.Create是传递一个对象当作参数来建立rooms、walls及doors;如此你可以以不同的参数来改变rooms、walls及doors的类。
请注意MazeFactory也就是工厂方法(Factory Method)的一个集合;这是最通常实现抽象工厂模式的方式。同时请注意MazeFactory不是一个抽象类(abstract class)它的行为包括抽象工厂(abstractFactory)及具体工厂(ContreteFactory);这也是另一种以抽象工厂实现简单应用系统的方式。因为MazeFactory是一种具体类包含所有的工厂方法所以容易以继承及覆盖的方式建立新的MazeFactory。
代码:

unit uMazeFactory;

interface

uses
Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls;

type
{房间的四个方向}
TDirection = (North = 0,South = 1,East = 2,West = 3);

const
DirectionNames: array[TDirection] of string = ('北', '南', '东', '西');

type
{咒语}
TSpell = class
private
FKey: string;
public
property Key: string read FKey write FKey;
end;

{迷宫构件}
TMapSite = class
private
FStateMsg: string;
public
function Enter: Boolean; virtual; abstract;
//---
property StateMsg: string read FStateMsg write FStateMsg;
end;
{房间}
TRoom = class(TMapSite)
private
FSides: array[TDirection] of TMapSite;
FRoomNumber: Integer;
protected
function GetSides(Direction: TDirection): TMapSite;
procedure SetSides(Direction: TDirection; const Value: TMapSite);
public
constructor Create(ARoomNumber: integer);
destructor Destroy; override;
//---
function Enter: Boolean; override;
//---
property RoomNumber: Integer read FRoomNumber;
property Sides[Direction: TDirection]: TMapSite read GetSides write SetSides;
end;
TRoomWithABomb = class(TRoom)
private
FBomb: boolean;
public
constructor Create(ARoomNumber: integer; Bombed: boolean = false);
//---
procedure Initialize1(Bombed: boolean);
function HasBomb(): Boolean;
function Enter: Boolean; override;
end;
TEnchantedRoom = class(TRoom)
private
FSpell: TSpell;
public
constructor Create(ARoomNumber: integer; Spell: TSpell = nil);
destructor Destroy; override;
//---
function Enter: Boolean; override;
//---
function HasSpell(): boolean;
function PickUpSpell(): TSpell;
end;
{墙壁}
TWall = class(TMapSite)
public
function Enter: Boolean; override;
end;
TBombedWall = class(TWall)
private
FBomb: boolean;
public
constructor Create(Bombed: boolean = false);
//---
function Enter: Boolean; override;
procedure Initialize1(Bombed: boolean);
end;
{门}
TDoor = class(TMapSite)
private
FRoom1,FRoom2: TRoom;
//--门是否开启
FIsOpen: Boolean;
procedure Initialize(room1,room2: TRoom);
public
constructor Create(room1,room2: TRoom); virtual;
destructor Destroy; override;
//---
function Enter: Boolean; override;
{从一个房间(传入参数)进入另一个房间(输出结果)}
function OtherSideFrom(Room: TRoom): TRoom;
end;
TDoorNeedingSpell = class(TDoor)
private
FSpell: TSpell;
function TrySpell(Spell: TSpell): boolean;
public
constructor Create(room1,room2: TRoom); override;
destructor Destroy; override;
//---
function Enter: Boolean; override;
end;
TRoomList = class
private
FItemList: TList;
function GetCount: Integer;
function GetItems(Index: integer): TRoom;
protected
procedure Clear;
public
constructor Create;
destructor Destroy; override;
//---
function Add(const Room: TRoom): integer;
//---
property Count: Integer read GetCount;
property Items[Index: integer]: TRoom read GetItems;
end;

{迷宫}
TMaze = class
private
FRooms: TRoomList;
public
constructor Create;
destructor Destroy; override;
//---
{在迷宫中加入一个房间}
procedure AddRoom(Room: TRoom);
{根据房间编号取得房间}
function RoomNo(RoomNumber: Integer): TRoom;
end;
{迷宫构件工厂}
TMazeFactory = class
protected
function MakeDoor(r1,r2: TRoom): TDoor; virtual;
function MakeMaze: TMaze; virtual;
function MakeRoom(ARoomNumber: integer): TRoom; virtual;
function MakeWall: TWall; virtual;
end;
{炸弹迷宫构件工厂}
TBombedMazeFactory = class(TMazeFactory)
protected
function MakeRoom(ARoomNumber: integer): TRoom; override;
function MakeWall(): TWall; override;
end;
{魔法迷宫构件工厂}
TEnchantedMazeFactory = class(TMazeFactory)
private
function CastSpell(): TSpell;
protected
function MakeRoom(ARoomNumber: integer): TRoom; override;
function MakeDoor(r1,r2: TRoom): TDoor; override;
end;

{迷宫游戏}
TMazeGame = class
public
function CreateMaze(factory: TMazeFactory): TMaze;
end;

var
CurSpell: TSpell;

implementation

constructor TRoom.Create(ARoomNumber: integer);
//---
procedure _InitSides;
var
Direction: TDirection;
begin
for Direction := Low(FSides) to High(FSides) do
FSides[Direction] := nil;
end;
begin
inherited Create;
//---
FRoomNumber := ARoomNumber;
//---
_InitSides;
end;

destructor TRoom.Destroy;
//---
procedure _ClearSides;
var
Direction: TDirection;
begin
for Direction := Low(FSides) to High(FSides) do
begin
if FSides[Direction] <> nil then
FSides[Direction].Free;
end;
end;
begin
_ClearSides;
//---
inherited;
end;

function TRoom.Enter: Boolean;
begin
self.StateMsg := format('进入房间%d', [FRoomNumber]);
Result := true;
end;

function TRoom.GetSides(Direction: TDirection): TMapSite;
begin
Result := FSides[Direction];
end;

procedure TRoom.SetSides(Direction: TDirection; const Value: TMapSite);
begin
FSides[Direction] := Value;
end;

function TWall.Enter: Boolean;
begin
self.StateMsg := '碰到墙';
Result := false;
end;

constructor TDoor.Create;
begin
inherited Create;
//---
Initialize(room1,room2);
end;

destructor TDoor.Destroy;
//---
procedure _ClearDoor(Room: TRoom);
var
Direction: TDirection;
begin
if Room <> nil then
begin
with Room do
begin
for Direction := Low(TDirection) to High(TDirection) do
begin
if Sides[Direction] = self then
begin
Sides[Direction] := nil;
exit;
end;
end;
end;
end;
end;
begin
_ClearDoor(FRoom1);
_ClearDoor(FRoom2);
//---
inherited;
end;

function TDoor.Enter: Boolean;
begin
self.StateMsg := '碰到门';
Result := true;
end;

procedure TDoor.Initialize(room1,room2: TRoom);
begin
FRoom1 := room1;
FRoom2 := room2;
FIsOpen := False;
end;

function TDoor.OtherSideFrom(Room: TRoom): Troom;
begin
if Room = FRoom1 then
Result := FRoom2
else
Result := FRoom1;
end;

constructor TBombedWall.Create(Bombed: boolean);
begin
inherited Create;
//---
Initialize1(Bombed);
end;

function TBombedWall.Enter: Boolean;
begin
if FBomb then
begin
self.StateMsg := '碰到炸弹墙';
Result := false;
end
else
Result := inherited Enter;
end;

procedure TBombedWall.Initialize1(Bombed: boolean);
begin
FBomb := Bombed;
end;

constructor TDoorNeedingSpell.Create(room1,room2: TRoom);
begin
inherited;
//---
FSpell := TSpell.Create;
FSpell.Key := '123';
end;

destructor TDoorNeedingSpell.Destroy;
begin
FSpell.Free;
//---
inherited;
end;

function TDoorNeedingSpell.Enter: Boolean;
begin
Result := TrySpell(CurSpell);
if Result then
self.StateMsg := '碰到门,使用了正确的咒语卷轴'
else
self.StateMsg := '碰到门,使用了错误的咒语卷轴';
end;

function TDoorNeedingSpell.TrySpell(Spell: TSpell): boolean;
begin
Result := FSpell.Key = Spell.Key;
end;

constructor TRoomWithABomb.Create(ARoomNumber: integer; Bombed: boolean);
begin
inherited Create(ARoomNumber);
//---
Initialize1(Bombed);
end;

function TRoomWithABomb.Enter: Boolean;
begin
if HasBomb then
begin
self.StateMsg := format('进入有炸弹的房间%d', [FRoomNumber]);
Result := true;
end
else
Result := inherited Enter;
end;

function TRoomWithABomb.HasBomb: Boolean;
begin
Result := FBomb;
end;

procedure TRoomWithABomb.Initialize1(Bombed: boolean);
begin
FBomb := Bombed;
end;

constructor TEnchantedRoom.Create(ARoomNumber: integer; Spell: TSpell);
begin
inherited Create(ARoomNumber);
//---
FSpell := Spell;
end;

destructor TEnchantedRoom.Destroy;
begin
if FSpell <> nil then
FSpell.Free;
//---
inherited;
end;

function TEnchantedRoom.Enter: Boolean;
begin
if HasSpell then
begin
CurSpell := PickUpSpell;
self.StateMsg := format('进入房间%d,拿起咒语卷轴', [FRoomNumber]);
Result := true;
end
else
Result := inherited Enter;
end;

function TEnchantedRoom.HasSpell: boolean;
begin
Result := FSpell <> nil;
end;

function TEnchantedRoom.PickUpSpell: TSpell;
begin
Result := FSpell;
end;

constructor TMaze.Create;
begin
inherited;
//---
FRooms := TRoomList.Create;
end;

destructor TMaze.Destroy;
begin
FRooms.Free;
//---
inherited;
end;

procedure TMaze.AddRoom(Room: TRoom);
begin
FRooms.Add(Room);
end;

function TMaze.RoomNo(RoomNumber: Integer): TRoom;
var
i: Integer;
begin
Result := nil;
//---
with FRooms do
begin
for i := 0 to Count - 1 do
begin
if Items[i].Roomnumber = RoomNumber then
begin
Result := Items[i];
Exit;
end;
end;
end;
end;

function TMazeFactory.MakeDoor(r1,r2: TRoom): TDoor;
begin
Result := TDoor.Create(r1,r2);
end;

function TMazeFactory.MakeMaze: TMaze;
begin
Result := TMaze.Create;
end;

function TMazeFactory.MakeRoom(ARoomNumber: integer): TRoom;
begin
Result := TRoom.Create(ARoomNumber);
end;

function TMazeFactory.MakeWall: TWall;
begin
Result := TWall.Create;
end;

function TBombedMazeFactory.MakeWall(): TWall;
begin
Result := TBombedWall.Create;
end;

function TBombedMazeFactory.MakeRoom(ARoomNumber: integer): TRoom;
begin
Result := TRoomWithABomb.Create(ARoomNumber);
end;

function TEnchantedMazeFactory.MakeRoom(ARoomNumber: integer): TRoom;
begin
Result := TEnchantedRoom.Create(ARoomNumber,CastSpell);
end;

function TEnchantedMazeFactory.CastSpell(): TSpell;
begin
Result := TSpell.Create;
Result.Key := '123';
end;

function TEnchantedMazeFactory.MakeDoor(r1,r2: TRoom): TDoor;
begin
Result := TDoorNeedingSpell.Create(r1,r2);
end;

function TMazeGame.CreateMaze(factory: TMazeFactory): TMaze;
var
aMaze: TMaze;
r1,r2: Troom;
theDoor: TDoor;
begin
//---建构一个maze,有两个Room,一个Door,六面Wall
aMaze := factory.MakeMaze;
//---
r1 := factory.MakeRoom(1);
r2 := factory.MakeRoom(2);
//---
theDoor := factory.MakeDoor(r1,r2);
//---
aMaze.AddRoom(r1);
aMaze.AddRoom(r2);
//---
r1.SetSides(North,factory.MakeWall());
r1.SetSides(East,theDoor);
r1.SetSides(South,factory.MakeWall());
r1.SetSides(West,factory.MakeWall());
//---
r2.SetSides(North,factory.MakeWall());
r2.SetSides(East,factory.MakeWall());
r2.SetSides(South,factory.MakeWall());
r2.SetSides(West,theDoor);
//---
result := aMaze;
end;

constructor TRoomList.Create;
begin
inherited;
//---
FItemList := TList.Create;
end;

destructor TRoomList.Destroy;
begin
Clear;
FItemList.Free;
//---
inherited;
end;

function TRoomList.Add(const Room: TRoom): integer;
begin
if Assigned(Room) then
Result := FItemList.Add(Room)
else
Result := -1;
end;

procedure TRoomList.Clear;
var
i: Integer;
begin
with FItemList do
begin
for i := 0 to Count - 1 do
TObject(Items[i]).Free;
//---
Clear;
end;
end;

function TRoomList.GetCount: Integer;
begin
Result := FItemList.Count;
end;

function TRoomList.GetItems(Index: integer): TRoom;
begin
Result := FItemList[Index];
end;

end.

unit Unit2;

interface

uses
Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
Dialogs,StdCtrls,uMazeFactory;

type
TForm2 = class(TForm)
ListBox1: TListBox;
procedure FormDestroy(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure ListBox1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
private
FMazeGame: TMazeGame;
FMazeFactory: TMazeFactory;
FMaze: TMaze;
FCurRoom: TRoom;
public
{ Public declarations }
end;

var
Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormCreate(Sender: TObject);
begin
self.KeyPreview := true;
//---
FMazeGame := TMazeGame.Create;
//---
{FMazeFactory := TMazeFactory.Create;
FMaze := FMazeGame.CreateMaze(FMazeFactory); }
//---
FMazeFactory := TBombedMazeFactory.Create;
FMaze := FMazeGame.CreateMaze(FMazeFactory);
TRoomWithABomb(FMaze.RoomNo(2)).Initialize1(true);
//---
{FMazeFactory := TEnchantedMazeFactory.Create;
FMaze := FMazeGame.CreateMaze(FMazeFactory);}
//---
FCurRoom := FMaze.RoomNo(1);
with FCurRoom do
begin
Enter;
ListBox1.Items.Add(StateMsg);
end;
end;

procedure TForm2.FormDestroy(Sender: TObject);
begin
FMaze.Free;
FMazeFactory.Free;
FMazeGame.Free;
end;

procedure TForm2.FormKeyDown(Sender: TObject; var Key: Word; Shift:
TShiftState);
//---
procedure _EnterRoomSide(Direction: TDirection);
var
ARoom: TRoom;
begin
with FCurRoom do
begin
if Sides[Direction] <> nil then
begin
with Sides[Direction] do
begin
if Enter then
begin
ListBox1.Items.Add(DirectionNames[Direction] + ':' + StateMsg);
//---
if Sides[Direction] is TDoor then
begin
ARoom := TDoor(Sides[Direction]).OtherSideFrom(FCurRoom);
if ARoom <> nil then
begin
if ARoom.Enter then
FCurRoom := ARoom;
ListBox1.Items.Add(ARoom.StateMsg);
end;
end;
end
else
ListBox1.Items.Add(DirectionNames[Direction] + ':' + StateMsg);
end;
end;
end;
end;
begin
case Ord(Key) of
VK_LEFT: _EnterRoomSide(East);
VK_RIGHT: _EnterRoomSide(West);
VK_UP: _EnterRoomSide(South);
VK_DOWN: _EnterRoomSide(North);
end;
end;

procedure TForm2.ListBox1KeyDown(Sender: TObject; var Key: Word; Shift:
TShiftState);
begin
Key := 0;
end;

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