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

本文介绍了一个基于抽象工厂模式的迷宫游戏设计实例。通过不同类型的迷宫工厂创建包含房间、门和墙等元素的迷宫,并实现了特定的功能,如带有咒语的门和装有炸弹的房间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

CH341A编程器是一款广泛应用的通用编程设备,尤其在电子工程嵌入式系统开发领域中,它被用来烧录各种类型的微控制器、存储器其他IC芯片。这款编程器的最新版本为1.3,它的一个显著特点是增加了对25Q256等32M芯片的支持。 25Q256是一种串行EEPROM(电可擦可编程只读存储器)芯片,通常用于存储程序代码、配置数据或其他非易失性信息。32M在这里指的是存储容量,即该芯片可以存储32兆位(Mbit)的数据,换算成字节数就是4MB。这种大容量的存储器在许多嵌入式系统中都有应用,例如汽车电子、工业控制、消费电子设备等。 CH341A编程器的1.3版更新,意味着它可以与更多的芯片型号兼容,特别是针对32M容量的芯片进行了优化,提高了编程效率稳定性。26系列芯片通常指的是Microchip公司的25系列SPI(串行外围接口)EEPROM产品线,这些芯片广泛应用于各种需要小体积、低功耗非易失性存储的应用场景。 全功能版的CH341A编程器不仅支持25Q256,还支持其他大容量芯片,这意味着它具有广泛的兼容性,能够满足不同项目的需求。这包括但不限于微控制器、EPROM、EEPROM、闪存、逻辑门电路等多种类型芯片的编程。 使用CH341A编程器进行编程操作时,首先需要将设备通过USB连接到计算机,然后安装相应的驱动程序编程软件。在本例中,压缩包中的"CH341A_1.30"很可能是编程软件的安装程序。安装后,用户可以通过软件界面选择需要编程的芯片类型,加载待烧录的固件或数据,然后执行编程操作。编程过程中需要注意的是,确保正确设置芯片的电压、时钟频率等参数,以防止损坏芯片。 CH341A编程器1.3版是面向电子爱好者专业工程师的一款实用工具,其强大的兼容性易用性使其在众多编程器中脱颖而出。对于需要处理25Q256等32M芯片的项目,或者26系列芯片的编程工作,CH341A编程器是理想的选择。通过持续的软件更新升级,它保持了与现代电子技术同步,确保用户能方便地对各种芯片进行编程调试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值