《GOF设计模式》—原型(Prototype)—Delphi源码示例:基于原型的迷宫2

来源:互联网 发布:企业网络布线论文 编辑:程序博客网 时间:2024/05/21 17:57
示例:基于原型的迷宫2

实现:

你可以用MazeFactory来生成你需要的原型;例如,你可以提供名字#room来创建一个房间。MazeFactory有一个将名字映射为原型的字典partCatalogpartCatalogMake方法可以根据名称创建原型。

代码:

unit uMazePrototype2;

 

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

    {迷宫构件}

    TMapSite = class

    private

        FStateMsg: string;

    public

        function Enter: Boolean; virtual; abstract;

        function Clone: TMapSite; 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;

        procedure InitializeRoomNo(RoomNo: integer);

        function Clone: TMapSite; 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);

        //---

        function HasBomb(): Boolean;

        function Enter: Boolean; override;

        procedure Initialize(Bombed: boolean);

        function Clone: TMapSite; override;

    end;

    {墙壁}

    TWall = class(TMapSite)

    public

        function Enter: Boolean; override;

        function Clone: TMapSite; override;

    end;

    TBombedWall = class(TWall)

    private

        FBomb: boolean;

    public

        constructor Create(Bombed: boolean = false);

        //---

        function Enter: Boolean; override;

        procedure Initialize(Bombed: boolean);

        function Clone: TMapSite; override;

    end;

    {}

    TDoor = class(TMapSite)

    private

        FRoom1,FRoom2: TRoom;

        //--门是否开启

        FIsOpen: Boolean;

    public

        constructor Create(room1,room2: TRoom);

        destructor Destroy; override;

        //---

        {从一个房间(传入参数)进入另一个房间(输出结果)}

        function OtherSideFrom(Room: TRoom): TRoom;

        function Enter: Boolean; override;

        procedure Initialize(room1,room2: TRoom);

        function Clone: TMapSite; 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;

        function Clone: TMaze; virtual;

    end;

 

    TPartInfo = record

        PartName: string;

        PartTemplate: TMapSite;

    end;

    PPartInfo = ^TPartInfo;

 

    TPartCatalog = class

    private

        FDataList: TList;

        function GetParts(PartName: string): TMapSite;

        procedure SetParts(PartName: string; const Value: TMapSite);

        procedure Clear;

        function Find(const PartName: string): PPartInfo;

        procedure Add(const PartName: string; const PartTemplate: TMapSite);

    public

        constructor Create;

        destructor Destroy; override;

        //---

        property Parts[PartName: string]: TMapSite read GetParts write SetParts; default;

    end;

    {迷宫构件工厂}

    TMazeFactory = class

    private

        FPartCatalog: TPartCatalog;

    public

        constructor Create;

        destructor Destroy; override;

        //---

        procedure AddPart(PartTemplate: TMapSite; const PartName: string);

        function Make(const PartName: string): TMapSite; virtual;

        function MakeMaze(): TMaze; virtual;

    end;

 

    {迷宫游戏}

    TMazeGame = class

    public

        function CreateMaze(factory: TMazeFactory): TMaze;

    end;

 

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.GetSides(Direction: TDirection): TMapSite;

begin

    Result := FSides[Direction];

end;

 

procedure TRoom.SetSides(Direction: TDirection; const Value: TMapSite);

begin

    FSides[Direction] := Value;

end;

 

function TRoom.Enter: Boolean;

begin

    self.StateMsg := format('进入房间%d', [FRoomNumber]);

    Result := true;

end;

 

procedure TRoom.InitializeRoomNo(RoomNo: integer);

begin

    FRoomNumber := RoomNo;

end;

 

function TRoom.Clone: TMapSite;

begin

    result := TRoom.Create(self.RoomNumber);

end;

 

function TWall.Enter: Boolean;

begin

    self.StateMsg := '碰到墙';

    Result := false;

end;

 

function TWall.Clone: TMapSite;

begin

    Result := TWall.Create;

end;

 

constructor TDoor.Create;

begin

    inherited Create;

    //---

    self.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.Clone: TMapSite;

begin

    result := TDoor.Create(nil,nil);

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;

    //---

    self.Initialize(Bombed);

end;

 

function TBombedWall.Enter: Boolean;

begin

    if FBomb then

    begin

        self.StateMsg := '碰到炸弹墙';

        Result := false;

    end

    else

        Result := inherited Enter;

end;

 

procedure TBombedWall.Initialize(Bombed: boolean);

begin

    FBomb := Bombed;

end;

 

function TBombedWall.Clone: TMapSite;

var

    Wall: TBombedWall;

begin

    Wall := TBombedWall.Create;

    Wall.Initialize(self.FBomb);

    //---

    Result := Wall;

end;

 

constructor TRoomWithABomb.Create(ARoomNumber: integer; Bombed: boolean);

begin

    inherited Create(ARoomNumber);

    //---

    self.Initialize(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.Initialize(Bombed: boolean);

begin

    FBomb := Bombed;

end;

 

function TRoomWithABomb.Clone: TMapSite;

var

    Room: TRoomWithaBomb;

begin

    Room := TRoomWithaBomb.Create(self.RoomNumber);

    Room.Initialize(self.HasBomb);

    //---

    result := Room;

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 TMaze.Clone: TMaze;

begin

    Result := TMaze.Create;

end;

 

function TMazeGame.CreateMaze(factory: TMazeFactory): TMaze;

var

    aMaze: TMaze;

    r1,r2: TRoom;

    Door: TDoor;

begin

    //---建构一个maze,有两个Room,一个Door,六面Wall

    aMaze := factory.MakeMaze;

    //---

    r1 := factory.Make('#Room') as TRoom;

    r1.InitializeRoomNo(101);

    r2 := factory.Make('#Room') as TRoom;

    r2.InitializeRoomNo(201);

    //---

    Door := factory.Make('#Door') as TDoor;

    Door.Initialize(r1,r2);

    //---

    aMaze.AddRoom(r1);

    aMaze.AddRoom(r2);

    //---

    r1.SetSides(North,factory.Make('#Wall'));

    r1.SetSides(East,Door);

    r1.SetSides(South,factory.Make('#Wall'));

    r1.SetSides(West,factory.Make('#Wall'));

    //---

    r2.SetSides(North,factory.Make('#Wall'));

    r2.SetSides(East,factory.Make('#Wall'));

    r2.SetSides(South,factory.Make('#Wall'));

    r2.SetSides(West,Door);

    //---

    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;

 

constructor TPartCatalog.Create;

begin

    inherited;

    //---

    FDataList := TList.Create;

end;

 

destructor TPartCatalog.Destroy;

begin

    Clear;

    FDataList.Free;

    //---

    inherited;

end;

 

procedure TPartCatalog.Clear;

var

    i: Integer;

    pData: PPartInfo;

begin

    with FDataList do

    begin

        for i := 0 to Count - 1 do

        begin

            pData := Items[i];

            pData.PartTemplate.Free;

            dispose(pData);

        end;

        //---

        Clear;

    end;

end;

 

procedure TPartCatalog.Add(const PartName: string; const PartTemplate:

    TMapSite);

var

    pData: PPartInfo;

begin

    new(pData);

    //---

    pData.PartName := PartName;

    pData.PartTemplate := PartTemplate;

    //---

    FDataList.Add(pData);

end;

 

function TPartCatalog.Find(const PartName: string): PPartInfo;

var

    i: integer;

    pData: PPartInfo;

begin

    with FDataList do

    begin

        for i := 0 to Count - 1 do

        begin

            pData := Items[i];

            if pData.PartName = PartName then

            begin

                Result := pData;

                exit;

            end;

        end;

    end;

    //---

    Result := nil;

end;

 

function TPartCatalog.GetParts(PartName: string): TMapSite;

var

    pData: PPartInfo;

begin

    pData := Find(PartName);

    if pData = nil then

        Result := nil

    else

        Result := pData.PartTemplate;

end;

 

procedure TPartCatalog.SetParts(PartName: string; const Value: TMapSite);

var

    pData: PPartInfo;

begin

    pData := Find(PartName);

    if pData = nil then

        Add(PartName,Value)

    else

    begin

        pData.PartTemplate.Free;

        pData.PartTemplate := Value;

    end;

end;

 

constructor TMazeFactory.Create;

begin

    FPartCatalog := TPartCatalog.Create;

end;

 

destructor TMazeFactory.Destroy;

begin

    FPartCatalog.Free;

    //---

    inherited;

end;

 

procedure TMazeFactory.AddPart(PartTemplate: TMapSite; const PartName: string);

begin

    FPartCatalog.Parts[PartName] := PartTemplate;

end;

 

function TMazeFactory.Make(const PartName: string): TMapSite;

begin

    Result := FPartCatalog[PartName].Clone;

end;

 

function TMazeFactory.MakeMaze: TMaze;

begin

    Result := TMaze.Create;

end;

 

end.

 

unit Unit1;

 

interface

 

uses

    Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Dialogs,

    StdCtrls,uMazePrototype2;

 

type

    TForm1 = 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

    Form1: TForm1;

 

implementation

 

{$R *.DFM}

 

procedure TForm1.FormCreate(Sender: TObject);

begin

    self.KeyPreview := true;

    //---

    FMazeGame := TMazeGame.Create;

    //---

    FMazeFactory := TMazeFactory.Create;

    with FMazeFactory do

    begin

        //---使用基本迷宫组件原型

        AddPart(TDoor.Create(nil,nil),'#Door');

        AddPart(TWall.Create,'#Wall');

        AddPart(TRoom.Create(0),'#Room');

        //---使用有炸弹房及炸弹门的迷宫组件原型

        {AddPart(TDoor.Create(nil,nil),'#Door');

        AddPart(TBombedWall.Create(true),'#Wall');

        AddPart(TRoomWithaBomb.Create(0),'#Room');}

    end;

    //---

    FMaze := FMazeGame.CreateMaze(FMazeFactory);

    //---

    FCurRoom := FMaze.RoomNo(101);

    with FCurRoom do

    begin

        Enter;

        ListBox1.Items.Add(StateMsg);

    end;

end;

 

procedure TForm1.FormDestroy(Sender: TObject);

begin

    FMaze.Free;

    FMazeFactory.Free;

    FMazeGame.Free;

end;

 

procedure TForm1.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 TForm1.ListBox1KeyDown(Sender: TObject; var Key: Word; Shift:

    TShiftState);

begin

    Key := 0;

end;

 

end.

 

原创粉丝点击