2

我想创建一个对象工厂武器类,它可以实例化我分配给它的无限量的射弹类。武器类和射弹类被用作“抽象”类(我知道 Delphi 7 不支持抽象类)。

现在我不知道如何实现正确实例化 projectileType 的 Weapon.shoot()(SimpleWeapon 类使用 SimpleProjectile 作为 projectileType)

procedure Weapon.shoot();
var g : Projectile;
begin
        // instanciate ammo type
        g := projectileType.create();
        g.init();
end; 

首先, projectileType.create() 返回一个我不能直接分配给 Projectile 变量的 TObject,并且通过 projectileType(g) 转换 TObject 也不起作用。

其次,我怎样才能实现将 g 转换为 projectileType,以便我可以使用该特定类的 init() 方法而不是它的父类(Projectile)?

UML 图

4

4 回答 4

3

声明一个类类型SimpleProjectileClass = class of SimpleProjectile。然后让 projectType 返回该类型:projectType: SimpleProjectileClass

于 2013-05-26T14:42:43.067 回答
2

武器不需要知道它可以发射什么样的射弹。它只应该知道,开火/射击。

所以实施武器战略将是最好的建议

type
  TWeapon = class;

  IWeaponStrategy = interface
    ['{B47CD780-906D-4515-BDA6-1EC8118BC29E}']
    procedure Shoot( AWeapon : TWeapon );
  end;

  TWeapon = class
  private
    FStrategy : IWeaponStrategy;
  public
    procedure Shoot;

    procedure SetStrategy( AStrategy : IWeaponStrategy );
  end;

implementation

{ TWeapon }

procedure TWeapon.SetStrategy( AStrategy : IWeaponStrategy );
begin
  FStrategy := AStrategy;
end;

procedure TWeapon.Shoot;
begin
  FStrategy.Shoot( Self );
end;

要让武器发射子弹,请构建 WeaponBulletStrategy

type
  TWeaponBulletStrategy = class( TInterfacedObject, IWeaponStrategy )
  protected
    procedure Shoot( AWeapon : TWeapon );
  end;

implementation

procedure TWeaponBulletStrategy.Shoot( Aweapon : TWeapon );
begin
  // Build the Bullet Instance and initialize
end;

现在,您可以轻松更改武器射击行为或实现新的射弹类,而无需更改武器类。

于 2013-05-26T15:34:13.840 回答
2
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type

  TBaseProjectile=Class
     Procedure Init;
  End;

  TProjectile_1=Class(TBaseProjectile)
  End;

  TProjectile_2=Class(TBaseProjectile)
  End;

  TBaseProjectile_Class=Class of TBaseProjectile;
  TProjectile_1Class=Class of TProjectile_1;
  TProjectile_2Class=Class of TProjectile_2;

  TBaseWappon=Class
    FClassRef:TBaseProjectile_Class;
    protected
    public
    Constructor Create(ProjektileClass:TBaseProjectile_Class);virtual;
    Procedure Shoot;
  End;

  TWappon_1=Class(TBaseWappon)
    public
  End;

  TWappon_2=Class(TBaseWappon)
    public
  End;


  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TBaseProjectile.Init;
begin
    Showmessage(Classname);
end;



{ TBaseWappon }

constructor TBaseWappon.Create(ProjektileClass:TBaseProjectile_Class);
begin
   FClassRef:=ProjektileClass;
end;

procedure TBaseWappon.Shoot;
begin
  With FClassRef.Create do
    begin
    init;
    Free;
    end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  With TWappon_1.create(TProjectile_1) do
    begin
      Shoot;
      Free;
    end;
  With TWappon_2.create(TProjectile_2) do
    begin
      Shoot;
      Free;
    end;

end;

end.
于 2013-05-26T15:36:53.147 回答
0

这是我对问题的看法:

type
  TProjectile = class
  protected
    function GetDamage: Integer; virtual; abstract;
    function GetPenetration: Double; virtual; abstract;
  public
    procedure DoExtenalBallistics(WindSpeed, WindDirection: Real); virtual;
    procedure DoInternalBallistics(Acceleration: Real); virtual;
    procedure DoTerminalBallistics(TargetArmor: Real); virtual;
    property Damage: Integer read GetDamage;
    /// <summary>
    /// Sorry, can not resist ;-)
    /// </summary>
    property Penetration: Double read GetPenetration;
  end;

procedure TProjectile.DoExtenalBallistics(WindSpeed, WindDirection: Real);
begin
  // TODO : do parabolic travel within the gravity pull of Earth, affected by wind
end;

procedure TProjectile.DoInternalBallistics(Acceleration: Real);
begin
  // TODO : do gain kinetic energy in the acceleration chamber
end;

procedure TProjectile.DoTerminalBallistics(TargetArmor: Real);
begin
  // TODO : TargetHitPoitns - (Damage / (TargetArmor - Penetration)) or something
end;

type
  TProjectileType = class of TProjectile;

  TFirearm = class
  protected
    function GetSupportedProjectile: TProjectileType; virtual; abstract;
  public
    function CanShoot(Projectile: TProjectile): Boolean; virtual;
    procedure Shoot;
    property SupportedProjectile: TProjectileType read GetSupportedProjectile;
  end;

function TFirearm.CanShoot(Projectile: TProjectile): Boolean;
begin
  Result := Projectile is SupportedProjectile;
end;

procedure TFirearm.Shoot;
var
  Projectile: TProjectile;
begin
  Projectile := SupportedProjectile.Create;
  Projectile.DoInternalBallistics(CardridgePowder);
  Projectile.DoExtenalBallistics(Theatre.Wind.Speed, Theatre.Wind.Direction);
  Projectile.DoTerminalBallistics(Targer.Armors);
  { ... }
  { ofc is CanShoot returns false, then http://i192.photobucket.com/albums/z96/M4builder/destructivetestedbarrrels01copy.jpg and Firearm.Owner.Fingers - 5 }
end;

type
  TSmoothBoreProjectile = class(TProjectile)
  end;

  TBuckshot = class(TSmoothBoreProjectile)
  end;

  Flechette = class(TSmoothBoreProjectile)
  end;

  TShotgun = class(TFirearm)
  protected
    function GetSupportedProjectile: TProjectileType; override;
  end;

function TShotgun.GetSupportedProjectile: TProjectileType;
begin
  Result := TSmoothBoreProjectile;
end;

为了简洁起见,我省略了几个必需的覆盖(模型比原始类图大得多),并将您提出的Init方法替换为与实际射弹应该做什么相关的伪。

于 2013-05-26T19:04:23.027 回答