2013-05-26 4 views
2

Я хочу создать объект класса оружия, который может создать бесконечное количество класса снаряда, который я ему назначил. Класс оружия и класс снаряда используются как «абстрактные» классы (я знаю, что Delphi 7 не поддерживает абстрактные классы).Построение объекта, который поддерживает наследование

Теперь я donßt знаю, как реализовать Weapon.shoot(), что instanciates в projectileType правильно (Класс SimpleWeapon использует SimpleProjectile как projectileType)

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

Во-первых, projectileType.create() возвращает TObject, который Я не могу напрямую назначить переменную Projectile, и литье TObject с помощью projectileType (g) также не работает.

Во-вторых, как я могу достичь того, что g будет заброшен в тип projectileType, так что я могу использовать метод init() этого конкретного класса, а не его родительский (Projectile)?

UML diagram

+0

Пусть это будет Jagged Alliance 3, пожалуйста, дорогой Санта, пожалуйста ... – OnTheFly

ответ

3

Объявите тип класса SimpleProjectileClass = class of SimpleProjectile. Затем верните тип projectType этого типа: projectType: SimpleProjectileClass.

+0

Но не будет ли это жестко кодировать тип снаряда типа оружия? Я хочу, чтобы это была переменная, например, оружие может переключаться между разными типами снарядов. –

+2

Не так долго все налеты наследуют от SimpleProjectile. –

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; 

Теперь вы можете легко изменить поведение стрелять оружие или осуществить новый снаряд классов без изменения класса оружия.

+0

Ну, на самом деле стрельба из огнестрельного оружия знает. – OnTheFly

+0

Вы действительно думаете, что баррель и пуля разговаривают друг с другом? Барабан даже не сейчас, пуля загружена. Только когда оба находятся в правильном месте, будет взаимодействие. И это зависит от вас, какая пуля вы загружаете, баррель не волнует. –

+0

Стрельба из стального ВВ или флештета повредит ваш нарезной бочонок. Съемка правильной пули из ствола с гладким отверстием даст вам выдающийся спред. Да, настоящая баллистика зависит от типа снаряда и типа ствола. – OnTheFly

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. 
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 методы с псевдостями, связанные с тем, что должен делать фактический снаряд.

Смежные вопросы