我想创建一个对象工厂武器类,它可以实现我分配给它的无限量的射弹类。武器类和射弹类被用作“抽象”类(我知道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)?
答案 0 :(得分:3)
声明类类型SimpleProjectileClass = class of SimpleProjectile
。然后使projectType返回该类型:projectType: SimpleProjectileClass
。
答案 1 :(得分: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;
现在你可以轻松改变武器射击行为或实施新的射弹类而无需改变武器类别。
答案 2 :(得分: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.
答案 3 :(得分: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
方法。