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

31 篇文章 0 订阅
28 篇文章 0 订阅
  1. 示例:基于工厂方法的迷宫  
  2. 实现:.  
  3. 函数CreateMaze建造并返回一个迷宫。这个函数存在的一个问题是它对迷宫、房间、门和墙壁的类进行了硬编码。我们将引入工厂方法以使子类可以选择这些构件。  
  4. 首先,我们将在MazeGame中定义工厂方法以创建迷宫、房间、墙壁和门对象;每一个工厂方法返回一个给定类型的迷宫构件。MazeGame提供一些缺省的实现,它们返回最简单的迷宫、房间、墙壁和门。  
  5. 不同的游戏可以创建MazeGame的子类以特别指明一些迷宫的部件。MazeGame子类可以重定义一些或所有的工厂方法以指定产品中的变化。例如,一个BombedMazeGame可以重定义产品Room和Wall以返回爆炸后的变体。  
  6. 代码:  
  7.    
  8. unit uMaze;  
  9.    
  10. interface  
  11.    
  12. uses  
  13.     Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls;  
  14.    
  15. type  
  16.     {房间的四个方向}  
  17.     TDirection = (North = 0,South = 1,East = 2,West = 3);  
  18.    
  19. const  
  20.     DirectionNames: array[TDirection] of string = ('北''南''东''西');  
  21.    
  22. type  
  23.     {咒语}  
  24.     TSpell = class  
  25.     private  
  26.         FKey: string;  
  27.     public  
  28.         property Key: string read FKey write FKey;  
  29.     end;  
  30.    
  31.     {迷宫构件}  
  32.     TMapSite = class  
  33.     private  
  34.         FStateMsg: string;  
  35.     public  
  36.         function Enter: Boolean; virtual; abstract;  
  37.         //---  
  38.         property StateMsg: string read FStateMsg write FStateMsg;  
  39.     end;  
  40.     {房间}  
  41.     TRoom = class(TMapSite)  
  42.     private  
  43.         FSides: array[TDirection] of TMapSite;  
  44.         FRoomNumber: Integer;  
  45.     protected  
  46.         function GetSides(Direction: TDirection): TMapSite;  
  47.         procedure SetSides(Direction: TDirection; const Value: TMapSite);  
  48.     public  
  49.         constructor Create(ARoomNumber: integer);  
  50.         destructor Destroy; override;  
  51.         //---  
  52.         function Enter: Boolean; override;  
  53.         //---  
  54.         property RoomNumber: Integer read FRoomNumber;  
  55.         property Sides[Direction: TDirection]: TMapSite read GetSides write SetSides;  
  56.     end;  
  57.     TRoomWithABomb = class(TRoom)  
  58.     private  
  59.         FBomb: boolean;  
  60.     public  
  61.         constructor Create(ARoomNumber: integer; Bombed: boolean = false);  
  62.         //---  
  63.         procedure Initialize1(Bombed: boolean);  
  64.         function HasBomb(): Boolean;  
  65.         function Enter: Boolean; override;  
  66.     end;  
  67.     TEnchantedRoom = class(TRoom)  
  68.     private  
  69.         FSpell: TSpell;  
  70.     public  
  71.         constructor Create(ARoomNumber: integer; Spell: TSpell = nil);  
  72.         destructor Destroy; override;  
  73.         //---  
  74.         function Enter: Boolean; override;  
  75.         //---  
  76.         function HasSpell(): boolean;  
  77.         function PickUpSpell(): TSpell;  
  78.     end;  
  79.     {墙壁}  
  80.     TWall = class(TMapSite)  
  81.     public  
  82.         function Enter: Boolean; override;  
  83.     end;  
  84.     TBombedWall = class(TWall)  
  85.     private  
  86.         FBomb: boolean;  
  87.     public  
  88.         constructor Create(Bombed: boolean = false);  
  89.         //---  
  90.         function Enter: Boolean; override;  
  91.         procedure Initialize1(Bombed: boolean);  
  92.     end;  
  93.     {门}  
  94.     TDoor = class(TMapSite)  
  95.     private  
  96.         FRoom1,FRoom2: TRoom;  
  97.         //--门是否开启  
  98.         FIsOpen: Boolean;  
  99.         procedure Initialize(room1,room2: TRoom);  
  100.     public  
  101.         constructor Create(room1,room2: TRoom); virtual;  
  102.         destructor Destroy; override;  
  103.         //---  
  104.         function Enter: Boolean; override;  
  105.         {从一个房间(传入参数)进入另一个房间(输出结果)}  
  106.         function OtherSideFrom(Room: TRoom): TRoom;  
  107.     end;  
  108.     TDoorNeedingSpell = class(TDoor)  
  109.     private  
  110.         FSpell: TSpell;  
  111.         function TrySpell(Spell: TSpell): boolean;  
  112.     public  
  113.         constructor Create(room1,room2: TRoom); override;  
  114.         destructor Destroy; override;  
  115.         //---  
  116.         function Enter: Boolean; override;  
  117.     end;  
  118.     TRoomList = class  
  119.     private  
  120.         FItemList: TList;  
  121.         function GetCount: Integer;  
  122.         function GetItems(Index: integer): TRoom;  
  123.     protected  
  124.         procedure Clear;  
  125.     public  
  126.         constructor Create;  
  127.         destructor Destroy; override;  
  128.         //---  
  129.         function Add(const Room: TRoom): integer;  
  130.         //---  
  131.         property Count: Integer read GetCount;  
  132.         property Items[Index: integer]: TRoom read GetItems;  
  133.     end;  
  134.     {迷宫}  
  135.     TMaze = class  
  136.     private  
  137.         FRooms: TRoomList;  
  138.     public  
  139.         constructor Create;  
  140.         destructor Destroy; override;  
  141.         //---  
  142.         {在迷宫中加入一个房间}  
  143.         procedure AddRoom(Room: TRoom);  
  144.         {根据房间编号取得房间}  
  145.         function RoomNo(RoomNumber: Integer): TRoom;  
  146.     end;  
  147.     {迷宫游戏}  
  148.     TMazeGame = class  
  149.     protected  
  150.         function MakeMaze: TMaze; virtual;  
  151.         function MakeRoom(ARoomNumber: integer): TRoom; virtual;  
  152.         function MakeWall: TWall; virtual;  
  153.         function MakeDoor(r1,r2: TRoom): TDoor; virtual;  
  154.     public  
  155.         function CreateMaze: TMaze;  
  156.     end;  
  157.     {炸弹迷宫游戏}  
  158.     TBombedMazeGame = class(TMazeGame)  
  159.     protected  
  160.         function MakeRoom(ARoomNumber: integer): TRoom; override;  
  161.         function MakeWall(): TWall; override;  
  162.     end;  
  163.     {魔法迷宫游戏}  
  164.     TEnchantedMazeGame = class(TMazeGame)  
  165.     private  
  166.         function CastSpell(): TSpell;  
  167.     protected  
  168.         function MakeRoom(ARoomNumber: integer): TRoom; override;  
  169.         function MakeDoor(r1,r2: TRoom): TDoor; override;  
  170.     end;  
  171.    
  172. var  
  173.     CurSpell: TSpell;  
  174.    
  175. implementation  
  176.    
  177. constructor TRoom.Create(ARoomNumber: integer);  
  178.     //---  
  179.     procedure _InitSides;  
  180.     var  
  181.         Direction: TDirection;  
  182.     begin  
  183.         for Direction := Low(FSides) to High(FSides) do  
  184.             FSides[Direction] := nil;  
  185.     end;  
  186. begin  
  187.     inherited Create;  
  188.     //---  
  189.     FRoomNumber := ARoomNumber;  
  190.     //---  
  191.     _InitSides;  
  192. end;  
  193.    
  194. destructor TRoom.Destroy;  
  195.     //---  
  196.     procedure _ClearSides;  
  197.     var  
  198.         Direction: TDirection;  
  199.     begin  
  200.         for Direction := Low(FSides) to High(FSides) do  
  201.         begin  
  202.             if FSides[Direction] <> nil then  
  203.                 FSides[Direction].Free;  
  204.         end;  
  205.     end;  
  206. begin  
  207.     _ClearSides;  
  208.     //---  
  209.     inherited;  
  210. end;  
  211.    
  212. function TRoom.Enter: Boolean;  
  213. begin  
  214.     self.StateMsg := format('进入房间%d', [FRoomNumber]);  
  215.     Result := true;  
  216. end;  
  217.    
  218. function TRoom.GetSides(Direction: TDirection): TMapSite;  
  219. begin  
  220.     Result := FSides[Direction];  
  221. end;  
  222.    
  223. procedure TRoom.SetSides(Direction: TDirection; const Value: TMapSite);  
  224. begin  
  225.     FSides[Direction] := Value;  
  226. end;  
  227.    
  228. function TWall.Enter: Boolean;  
  229. begin  
  230.     self.StateMsg := '碰到墙';  
  231.     Result := false;  
  232. end;  
  233.    
  234. constructor TDoor.Create;  
  235. begin  
  236.     inherited Create;  
  237.     //---  
  238.     Initialize(room1,room2);  
  239. end;  
  240.    
  241. destructor TDoor.Destroy;  
  242.     //---  
  243.     procedure _ClearDoor(Room: TRoom);  
  244.     var  
  245.         Direction: TDirection;  
  246.     begin  
  247.         if Room <> nil then  
  248.         begin  
  249.             with Room do  
  250.             begin  
  251.                 for Direction := Low(TDirection) to High(TDirection) do  
  252.                 begin  
  253.                     if Sides[Direction] = self then  
  254.                     begin  
  255.                         Sides[Direction] := nil;  
  256.                         exit;  
  257.                     end;  
  258.                 end;  
  259.             end;  
  260.         end;  
  261.     end;  
  262. begin  
  263.     _ClearDoor(FRoom1);  
  264.     _ClearDoor(FRoom2);  
  265.     //---  
  266.     inherited;  
  267. end;  
  268.    
  269. function TDoor.Enter: Boolean;  
  270. begin  
  271.     self.StateMsg := '碰到门';  
  272.     Result := true;  
  273. end;  
  274.    
  275. procedure TDoor.Initialize(room1,room2: TRoom);  
  276. begin  
  277.     FRoom1 := room1;  
  278.     FRoom2 := room2;  
  279.     FIsOpen := False;  
  280. end;  
  281.    
  282. function TDoor.OtherSideFrom(Room: TRoom): Troom;  
  283. begin  
  284.     if Room = FRoom1 then  
  285.         Result := FRoom2  
  286.     else  
  287.         Result := FRoom1;  
  288. end;  
  289.    
  290. constructor TBombedWall.Create(Bombed: boolean);  
  291. begin  
  292.     inherited Create;  
  293.     //---  
  294.     Initialize1(Bombed);  
  295. end;  
  296.    
  297. function TBombedWall.Enter: Boolean;  
  298. begin  
  299.     if FBomb then  
  300.     begin  
  301.         self.StateMsg := '碰到炸弹墙';  
  302.         Result := false;  
  303.     end  
  304.     else  
  305.         Result := inherited Enter;  
  306. end;  
  307.    
  308. procedure TBombedWall.Intialize(Bombed: boolean);  
  309. begin  
  310.     FBomb := Bombed;  
  311. end;  
  312.    
  313. constructor TDoorNeedingSpell.Create(room1,room2: TRoom);  
  314. begin  
  315.     inherited;  
  316.     //---  
  317.     FSpell := TSpell.Create;  
  318.     FSpell.Key := '123';  
  319. end;  
  320.    
  321. destructor TDoorNeedingSpell.Destroy;  
  322. begin  
  323.     FSpell.Free;  
  324.     //---  
  325.     inherited;  
  326. end;  
  327.    
  328. function TDoorNeedingSpell.Enter: Boolean;  
  329. begin  
  330.     Result := TrySpell(CurSpell);  
  331.     if Result then  
  332.         self.StateMsg := '碰到门,使用了正确的咒语卷轴'  
  333.     else  
  334.         self.StateMsg := '碰到门,使用了错误的咒语卷轴';  
  335. end;  
  336.    
  337. function TDoorNeedingSpell.TrySpell(Spell: TSpell): boolean;  
  338. begin  
  339.     Result := FSpell.Key = Spell.Key;  
  340. end;  
  341.    
  342. constructor TRoomWithABomb.Create(ARoomNumber: integer; Bombed: boolean);  
  343. begin  
  344.     inherited Create(ARoomNumber);  
  345.     //---  
  346.     Initialize1(Bombed);  
  347. end;  
  348.    
  349. function TRoomWithABomb.Enter: Boolean;  
  350. begin  
  351.     if HasBomb then  
  352.     begin  
  353.         self.StateMsg := format('进入有炸弹的房间%d', [FRoomNumber]);  
  354.         Result := true;  
  355.     end  
  356.     else  
  357.         Result := inherited Enter;  
  358. end;  
  359.    
  360. function TRoomWithABomb.HasBomb: Boolean;  
  361. begin  
  362.     Result := FBomb;  
  363. end;  
  364.    
  365. procedure TRoomWithABomb.Intialize(Bombed: boolean);  
  366. begin  
  367.     FBomb := Bombed;  
  368. end;  
  369.    
  370. constructor TEnchantedRoom.Create(ARoomNumber: integer; Spell: TSpell);  
  371. begin  
  372.     inherited Create(ARoomNumber);  
  373.     //---  
  374.     FSpell := Spell;  
  375. end;  
  376.    
  377. destructor TEnchantedRoom.Destroy;  
  378. begin  
  379.     if FSpell <> nil then  
  380.         FSpell.Free;  
  381.     //---  
  382.     inherited;  
  383. end;  
  384.    
  385. function TEnchantedRoom.Enter: Boolean;  
  386. begin  
  387.     if HasSpell then  
  388.     begin  
  389.         CurSpell := PickUpSpell;  
  390.         self.StateMsg := format('进入房间%d,拿起咒语卷轴', [FRoomNumber]);  
  391.         Result := true;  
  392.     end  
  393.     else  
  394.         Result := inherited Enter;  
  395. end;  
  396.    
  397. function TEnchantedRoom.HasSpell: boolean;  
  398. begin  
  399.     Result := FSpell <> nil;  
  400. end;  
  401.    
  402. function TEnchantedRoom.PickUpSpell: TSpell;  
  403. begin  
  404.     Result := FSpell;  
  405. end;  
  406.    
  407. constructor TMaze.Create;  
  408. begin  
  409.     inherited;  
  410.     //---  
  411.     FRooms := TRoomList.Create;  
  412. end;  
  413.    
  414. destructor TMaze.Destroy;  
  415. begin  
  416.     FRooms.Free;  
  417.     //---  
  418.     inherited;  
  419. end;  
  420.    
  421. procedure TMaze.AddRoom(Room: TRoom);  
  422. begin  
  423.     FRooms.Add(Room);  
  424. end;  
  425.    
  426. function TMaze.RoomNo(RoomNumber: Integer): TRoom;  
  427. var  
  428.     i: Integer;  
  429. begin  
  430.     Result := nil;  
  431.     //---  
  432.     with FRooms do  
  433.     begin  
  434.         for i := 0 to Count - 1 do  
  435.         begin  
  436.             if Items[i].Roomnumber = RoomNumber then  
  437.             begin  
  438.                 Result := Items[i];  
  439.                 Exit;  
  440.             end;  
  441.         end;  
  442.     end;  
  443. end;  
  444.    
  445. function TMazeGame.CreateMaze: TMaze;  
  446. var  
  447.     aMaze: TMaze;  
  448.     r1,r2: Troom;  
  449.     theDoor: TDoor;  
  450. begin  
  451.     //---建构一个maze,有两个Room,一个Door,六面Wall  
  452.     aMaze := MakeMaze;  
  453.     //---  
  454.     r1 := MakeRoom(1);  
  455.     r2 := MakeRoom(2);  
  456.     //---  
  457.     theDoor := MakeDoor(r1,r2);  
  458.     //---  
  459.     aMaze.AddRoom(r1);  
  460.     aMaze.AddRoom(r2);  
  461.     //---  
  462.     r1.SetSides(North,MakeWall());  
  463.     r1.SetSides(East,theDoor);  
  464.     r1.SetSides(South,MakeWall());  
  465.     r1.SetSides(West,MakeWall());  
  466.     //---  
  467.     r2.SetSides(North,MakeWall());  
  468.     r2.SetSides(East,MakeWall());  
  469.     r2.SetSides(South,MakeWall());  
  470.     r2.SetSides(West,theDoor);  
  471.     //---  
  472.     result := aMaze;  
  473. end;  
  474.    
  475. function TMazeGame.MakeMaze: TMaze;  
  476. begin  
  477.     Result := TMaze.Create;  
  478. end;  
  479.    
  480. function TMazeGame.MakeRoom(ARoomNumber: integer): TRoom;  
  481. begin  
  482.     Result := TRoom.Create(ARoomNumber);  
  483. end;  
  484.    
  485. function TMazeGame.MakeWall: TWall;  
  486. begin  
  487.     Result := TWall.Create;  
  488. end;  
  489.    
  490. function TMazeGame.MakeDoor(r1,r2: TRoom): TDoor;  
  491. begin  
  492.     Result := TDoor.Create(r1,r2);  
  493. end;  
  494.    
  495. function TBombedMazeGame.MakeWall(): TWall;  
  496. begin  
  497.     Result := TBombedWall.Create;  
  498. end;  
  499.    
  500. function TBombedMazeGame.MakeRoom(ARoomNumber: integer): TRoom;  
  501. begin  
  502.     Result := TRoomWithABomb.Create(ARoomNumber);  
  503. end;  
  504.    
  505. function TEnchantedMazeGame.MakeRoom(ARoomNumber: integer): TRoom;  
  506. begin  
  507.     Result := TEnchantedRoom.Create(ARoomNumber,CastSpell);  
  508. end;  
  509.    
  510. function TEnchantedMazeGame.CastSpell(): TSpell;  
  511. begin  
  512.     Result := TSpell.Create;  
  513.     Result.Key := '123';  
  514. end;  
  515.    
  516. function TEnchantedMazeGame.MakeDoor(r1,r2: TRoom): TDoor;  
  517. begin  
  518.     Result := TDoorNeedingSpell.Create(r1,r2);  
  519. end;  
  520.    
  521. constructor TRoomList.Create;  
  522. begin  
  523.     inherited;  
  524.     //---  
  525.     FItemList := TList.Create;  
  526. end;  
  527.    
  528. destructor TRoomList.Destroy;  
  529. begin  
  530.     Clear;  
  531.     FItemList.Free;  
  532.     //---  
  533.     inherited;  
  534. end;  
  535.    
  536. function TRoomList.Add(const Room: TRoom): integer;  
  537. begin  
  538.     if Assigned(Room) then  
  539.         Result := FItemList.Add(Room)  
  540.     else  
  541.         Result := -1;  
  542. end;  
  543.    
  544. procedure TRoomList.Clear;  
  545. var  
  546.     i: Integer;  
  547. begin  
  548.     with FItemList do  
  549.     begin  
  550.         for i := 0 to Count - 1 do  
  551.             TObject(Items[i]).Free;  
  552.         //---  
  553.         Clear;  
  554.     end;  
  555. end;  
  556.    
  557. function TRoomList.GetCount: Integer;  
  558. begin  
  559.     Result := FItemList.Count;  
  560. end;  
  561.    
  562. function TRoomList.GetItems(Index: integer): TRoom;  
  563. begin  
  564.     Result := FItemList[Index];  
  565. end;  
  566.    
  567. end.  
  568.    
  569. unit Unit1;  
  570.    
  571. interface  
  572.    
  573. uses  
  574.     Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,  
  575.     Dialogs,StdCtrls,Menus,uMaze;  
  576.    
  577. type  
  578.     TForm1 = class(TForm)  
  579.         ListBox1: TListBox;  
  580.         procedure FormCreate(Sender: TObject);  
  581.         procedure FormDestroy(Sender: TObject);  
  582.         procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);  
  583.         procedure ListBox1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);  
  584.     private  
  585.         FMazeGame: TMazeGame;  
  586.         FMaze: TMaze;  
  587.         FCurRoom: TRoom;  
  588.     public  
  589.     { Public declarations }  
  590.     end;  
  591.    
  592. var  
  593.     Form1: TForm1;  
  594.    
  595. implementation  
  596.    
  597. {$R *.dfm}  
  598.    
  599. procedure TForm1.FormCreate(Sender: TObject);  
  600. begin  
  601.     self.KeyPreview := true;  
  602.     //---  
  603.     {FMazeGame := TMazeGame.Create; 
  604.     FMaze := FMazeGame.CreateMaze;}  
  605.     //---  
  606.     {FMazeGame := TBombedMazeGame.Create; 
  607.     FMaze := FMazeGame.CreateMaze; 
  608.     TRoomWithABomb(FMaze.RoomNo(2)).Initialize1(true);}  
  609.     //---  
  610.     FMazeGame := TEnchantedMazeGame.Create;  
  611.     FMaze := FMazeGame.CreateMaze;  
  612.     //---  
  613.     FCurRoom := FMaze.RoomNo(1);  
  614.     with FCurRoom do  
  615.     begin  
  616.         Enter;  
  617.         ListBox1.Items.Add(StateMsg);  
  618.     end;  
  619. end;  
  620.    
  621. procedure TForm1.FormDestroy(Sender: TObject);  
  622. begin  
  623.     FMaze.Free;  
  624.     FMazeGame.Free;  
  625. end;  
  626.    
  627. procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift:  
  628.     TShiftState);  
  629.     //---  
  630.     procedure _EnterRoomSide(Direction: TDirection);  
  631.     var  
  632.         ARoom: TRoom;  
  633.     begin  
  634.         with FCurRoom do  
  635.         begin  
  636.             if Sides[Direction] <> nil then  
  637.             begin  
  638.                 with Sides[Direction] do  
  639.                 begin  
  640.                     if Enter then  
  641.                     begin  
  642.                         ListBox1.Items.Add(DirectionNames[Direction] + ':' + StateMsg);  
  643.                         //---  
  644.                         if Sides[Direction] is TDoor then  
  645.                         begin  
  646.                             ARoom := TDoor(Sides[Direction]).OtherSideFrom(FCurRoom);  
  647.                             if ARoom <> nil then  
  648.                             begin  
  649.                                 if ARoom.Enter then  
  650.                                     FCurRoom := ARoom;  
  651.                                 ListBox1.Items.Add(ARoom.StateMsg);  
  652.                             end;  
  653.                         end;  
  654.                     end  
  655.                     else  
  656.                         ListBox1.Items.Add(DirectionNames[Direction] + ':' + StateMsg);  
  657.                 end;  
  658.             end;  
  659.         end;  
  660.     end;  
  661. begin  
  662.     case Ord(Key) of  
  663.         VK_LEFT: _EnterRoomSide(East);  
  664.         VK_RIGHT: _EnterRoomSide(West);  
  665.         VK_UP: _EnterRoomSide(South);  
  666.         VK_DOWN: _EnterRoomSide(North);  
  667.     end;  
  668. end;  
  669.    
  670. procedure TForm1.ListBox1KeyDown(Sender: TObject; var Key: Word; Shift:  
  671.     TShiftState);  
  672. begin  
  673.     Key := 0;  
  674. end;  
  675.    
  676. end.  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值