2013-04-30 2 views
2

У меня есть weapon класса, projectile класса и ballistic weapon класса, который наследует от weapon, ballistic projectile класса наследуют от projectile и weapon класса имеет свойство снаряда, который получает и устанавливает снаряд для оружия.Переопределить унаследованное свойство или создать новый, если он более конкретный?

баллистического оружие наследует это, однако баллистическое оружие не будет иметь только любое оружие имеет баллистический снаряд (отличный от скажу лазерный снаряда, который не будет иметь скорость снаряда, потому что это мгновенное воздействие)

So если я решил переопределить свойство оружия, установщик может вызвать проблемы, потому что

public Projectile weaponprojectile 
{ 
// getter/setter 
} 

принимает только общий снаряд. Грейт-переопределение будет работать нормально, потому что возврат мяча-снаряда по-прежнему возвращает базовый снаряд, он имеет все, что делает снаряд, а затем и некоторые. Однако сеттер не будет в порядке. Не только любой снаряд может быть установлен как баллистический снаряд.

Так что, если я использую переопределение, это правильный способ подтвердить тип баллистического и статического преобразования, или я должен попробовать что-то еще?

Если я не использовать переопределение, но сделать новый сеттер я волнуюсь, я бы в конечном итоге с этим оружием, которое было 2 почти идентичные свойства,

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

Я новичок в использовании наследования, поэтому, если бы кто-то мог дать мне руководство в основном о том, что вы делаете, если у вас есть абстрактный класс с общей переменной, и вы наследуете этот класс и переменную и имеете более конкретный тип переменной.

+0

Вы можете разместить пример кода ,пожалуйста? – Frank59

ответ

2

Вы можете использовать covariance для обеспечения «специализированных» снарядов в свойствах оружия, в то же время сохраняя способность лечить оружие как часть одной и той же иерархии:

interface IProjectile { 
    string Name { get; } 
} 

// Note the `out` keyword below: 
interface IWeapon<out TProjectile> where TProjectile : IProjectile { 
    TProjectile Projectile { get; } 
} 

class BallisticMissile : IProjectile { 
    public double Speed { get; set; } 
    public string Name { get { return "ballistic missile"; } } 
} 

class BallisticWeapon : IWeapon<BallisticMissile> { 
    public BallisticMissile Projectile { get; set; } 
} 

class LaserBeam : IProjectile { 
    public double WaveLength; 
    public string Name { get { return "laser beam"; } } 
} 

class LaserWeapon : IWeapon<LaserBeam> { 
    public LaserBeam Projectile { get; set; } 
} 

class Program { 

    static void Main(string[] args) { 

     // Manipulate the ballistic weapon in its own specific way: 
     var ballisticWeapon = new BallisticWeapon(); 
     ballisticWeapon.Projectile = new BallisticMissile(); 
     ballisticWeapon.Projectile.Speed = 2000; 

     // Manipulate the laser weapon in its own specific way: 
     var laserWeapon = new LaserWeapon(); 
     laserWeapon.Projectile = new LaserBeam(); 
     laserWeapon.Projectile.WaveLength = 400; 

     // But you can still use both of them as an IWeapon<IProjectile>: 
     var weapons = new List<IWeapon<IProjectile>>(); 
     weapons.Add(ballisticWeapon); 
     weapons.Add(laserWeapon); 
     foreach (var weapon in weapons) 
      Console.WriteLine(weapon.Projectile.Name); 

    } 

} 
+0

Спасибо за этот пост Я думал, что это умное использование ковариации, которую я не рассматривал (или, может быть, я просто не понимал глубоких приложений ковариации :)). Для моего собственного наставления этот подход не означает, что если вы захотите расширить IWeapon позже с чем-то вроде TExplosion, вам нужно будет посетить каждую реализацию IWeapon в проекте? Или я чего-то не хватает? –

+0

@MattJohnson Ну, всякий раз, когда к интерфейсу добавляется новый член, все классы, реализующие этот интерфейс, должны быть изменены для реализации этого нового члена независимо от ковариации. –

+0

Итак, если бы мы искали будущее расширение, вы бы рекомендовали переместить в BallisticWeapon и оставить IWeapon простым интерфейсом или это испортит преимущества ковариации? –

1

Существует множество способов проектирования, что вы ищете. Если бы это был я, я бы, вероятно, использовал интерфейсы, чтобы избежать проблем наследования, которые вы описываете. Я также могу использовать эти различные типы оружия, описанные в XML-файле, который загружается во время выполнения. Однако что-то вроде этого будет работать на основе того, что вы описываете:

public interface IWeapon 
    { 
     int WeaponDamage { get; } 
    } 

    public interface IBalisticWeapon 
    { 
     int BallisticDamage { get; } 
    } 

    public interface IProjectile 
    { 
     int ProjectileDamage { get; } 
    } 

    public abstract class WeaponBase: IWeapon 
    { 
     public virtual int WeaponDamage { get { return 100; } }//base damage 
    } 

    public class Arrow : WeaponBase, IProjectile, IBalisticWeapon 
    { 
     public override int WeaponDamage { get { return this.BallisticDamage; } } 

     public int BallisticDamage { get { return 10; } } 

     public int ProjectileDamage { get { return this.BallisticDamage; } } 
    } 

    public class BattleAxe : WeaponBase 
    { 
     //this inherits Weapon Damage from WeaponBase 
    } 

    public class Rock : WeaponBase, IProjectile 
    { 
     public override int WeaponDamage { get { return this.ProjectileDamage; } } 
     public int ProjectileDamage { get { return 10; } } 
    } 

    class Program 
    { 
     static WeaponBase GetWeapon() 
     { 
      return new Arrow(); 
     } 

     static void Main(string[] args) 
     { 
      int damage = 0; 
      IWeapon weapon = GetWeapon(); 
      if (weapon is IProjectile) 
      { 
       damage = (weapon as IProjectile).ProjectileDamage; 
      } 
      else if (weapon is IBalisticWeapon) 
      { 
       damage = (weapon as IBalisticWeapon).BallisticDamage; 
      } 
      else 
      { 
       damage = (weapon as IWeapon).WeaponDamage; 
      } 
     } 
    } 
1

Возможно, вы захотите опубликовать все участвующие классы. Если я понимаю вас, я бы подумал, что у вас есть метод Fire в классе Weapon (или какой-то метод, который использует weaponprojectile). Вероятно, вы хотите переопределить этот метод. Чтобы обнаружить тип и принять меры, это не лучший дизайн. Лучше инкапсулировать, какие изменения (в данном случае - код Fire/Attack/Whatever) и Setter. Пример

public class BalisticWeapon 
{ 
    public BalisticWeapon(){} 

    public override BalisticProjectile weaponprojectile 
    { 
    get { return Base.weaponprojectile; } 
    set { Base.Weaponprojectile = value; } 
    } 

    public override void Fire() 
    { 
    //Handle special case for Firing BalisticProjectile 
    } 
} 
Смежные вопросы