本文共 14328 字,大约阅读时间需要 47 分钟。
示例:基于工厂方法的迷宫实现:.函数CreateMaze建造并返回一个迷宫。这个函数存在的一个问题是它对迷宫、房间、门和墙壁的类进行了硬编码。我们将引入工厂方法以使子类可以选择这些构件。首先,我们将在MazeGame中定义工厂方法以创建迷宫、房间、墙壁和门对象;每一个工厂方法返回一个给定类型的迷宫构件。MazeGame提供一些缺省的实现,它们返回最简单的迷宫、房间、墙壁和门。不同的游戏可以创建MazeGame的子类以特别指明一些迷宫的部件。MazeGame子类可以重定义一些或所有的工厂方法以指定产品中的变化。例如,一个BombedMazeGame可以重定义产品Room和Wall以返回爆炸后的变体。代码: unit uMaze; 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; {迷宫游戏} TMazeGame = class protected function MakeMaze: TMaze; virtual; function MakeRoom(ARoomNumber: integer): TRoom; virtual; function MakeWall: TWall; virtual; function MakeDoor(r1,r2: TRoom): TDoor; virtual; public function CreateMaze: TMaze; end; {炸弹迷宫游戏} TBombedMazeGame = class(TMazeGame) protected function MakeRoom(ARoomNumber: integer): TRoom; override; function MakeWall(): TWall; override; end; {魔法迷宫游戏} TEnchantedMazeGame = class(TMazeGame) private function CastSpell(): TSpell; protected function MakeRoom(ARoomNumber: integer): TRoom; override; function MakeDoor(r1,r2: TRoom): TDoor; override; 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.Intialize(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.Intialize(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 TMazeGame.CreateMaze: TMaze;var aMaze: TMaze; r1,r2: Troom; theDoor: TDoor;begin //---建构一个maze,有两个Room,一个Door,六面Wall aMaze := MakeMaze; //--- r1 := MakeRoom(1); r2 := MakeRoom(2); //--- theDoor := MakeDoor(r1,r2); //--- aMaze.AddRoom(r1); aMaze.AddRoom(r2); //--- r1.SetSides(North,MakeWall()); r1.SetSides(East,theDoor); r1.SetSides(South,MakeWall()); r1.SetSides(West,MakeWall()); //--- r2.SetSides(North,MakeWall()); r2.SetSides(East,MakeWall()); r2.SetSides(South,MakeWall()); r2.SetSides(West,theDoor); //--- result := aMaze;end; function TMazeGame.MakeMaze: TMaze;begin Result := TMaze.Create;end; function TMazeGame.MakeRoom(ARoomNumber: integer): TRoom;begin Result := TRoom.Create(ARoomNumber);end; function TMazeGame.MakeWall: TWall;begin Result := TWall.Create;end; function TMazeGame.MakeDoor(r1,r2: TRoom): TDoor;begin Result := TDoor.Create(r1,r2);end; function TBombedMazeGame.MakeWall(): TWall;begin Result := TBombedWall.Create;end; function TBombedMazeGame.MakeRoom(ARoomNumber: integer): TRoom;begin Result := TRoomWithABomb.Create(ARoomNumber);end; function TEnchantedMazeGame.MakeRoom(ARoomNumber: integer): TRoom;begin Result := TEnchantedRoom.Create(ARoomNumber,CastSpell);end; function TEnchantedMazeGame.CastSpell(): TSpell;begin Result := TSpell.Create; Result.Key := '123';end; function TEnchantedMazeGame.MakeDoor(r1,r2: TRoom): TDoor;begin Result := TDoorNeedingSpell.Create(r1,r2);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 Unit1; interface uses Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms, Dialogs,StdCtrls,Menus,uMaze; type TForm1 = class(TForm) ListBox1: TListBox; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure ListBox1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); private FMazeGame: TMazeGame; 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; FMaze := FMazeGame.CreateMaze;} //--- {FMazeGame := TBombedMazeGame.Create; FMaze := FMazeGame.CreateMaze; TRoomWithABomb(FMaze.RoomNo(2)).Initialize1(true);} //--- FMazeGame := TEnchantedMazeGame.Create; FMaze := FMazeGame.CreateMaze; //--- FCurRoom := FMaze.RoomNo(1); with FCurRoom do begin Enter; ListBox1.Items.Add(StateMsg); end;end; procedure TForm1.FormDestroy(Sender: TObject);begin FMaze.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.
转载地址:http://guymf.baihongyu.com/