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

示例:基于抽象工厂的迷宫
实现:
   如果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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值