13

I've read some on properties and i'm not sure if thats what i want or not. Basically i have an abstract projectile class so that all "bullets" have a common implementation That any "weapon" they are attached to can expect to be able to use.

I know you can declare an abstract class and force the functions you declare inside it to be defined. I'd like the same thing with the variables (i think, obviously this functionality doesn't seem to exist so perhaps i'm thinking about the solution wrong)

My issue is that since all "bullets" should have a damage i'd like to be forced to declare in code the damage value of a bullet.

There may be a case where the round is from a stun gun and it does no damage but I feel that I should still be made to declare it for 2 reasons.

  1. The explicit declaration in the code of this does zero damage is worth the one line of code. You don't have to go well I guess it does none since it says nothing about damage it's explicitly stated.

  2. Debugging (this is the main reason the other is minor) I want to be forced, so I don't forget. I don't want to mistype the variable name or forget to assign a value altogether and hunt for a half hour trying to figure out why my rocket or missile or bullet or whatever isn't doing any damage or is doing exactly 1 or the amount of the last projectile I used or whatever the default value of the float variable I declared in the abstract class ends up as. I want to be thrown an error right away telling me I can't continue until my new bullet has a damage.

Dinah
  • 52,922
  • 30
  • 133
  • 149
sparkzbarca
  • 301
  • 1
  • 3
  • 9

3 Answers3

12

Properties are what you're looking for. on an interface you would just do something like this:

public interface IProjectile 
{
    string Name { get; }

    int Damage { get; }

    void Fire();
}

Only the get method has to be defined on the interface because you only need the consumer of the interface to read from the damage property, and you'd prefer to not allow the consumer to write the damage value.

The implementation would be something like this:

public class Bullet : IProjectile 
{
    public string Name { get { return "Bullet"; } }
    public string Damage { get { return 5; } }

    public void Fire() 
    {
        Console.WriteLine("Did {0} damage.",Damage);
    }    
}
nathan gonzalez
  • 11,817
  • 4
  • 41
  • 57
  • This can also be done with an `abstract` class (which _might_ be in line with what user53961 needs), just declare the `Damage` property as `abstract` as well. EDIT: Just to be clear though, I favour the interface approach in this case. (because would an RPG with momentum and physics be considered a "bullet"?) – Chris Sinclair Apr 27 '13 at 01:29
11

Here is a bit more detail on how to implement this:

public abstract class Projectile {
  public Name { get{return GetType().Name;}  }
  public abstract int Damgage { get; }
}

public Bullet202: Projectile {
  public override int Damage { get{return 5;} }
}

public Bullet303: Projectile {
  public override int Damage { get{return 8;} }
}

Distinction between using an interface or an abstract class as a basis: An abstract class ia a shared implementation, an interface is a shared contract. They share some commonality, but meet different requirements. For instance, you might want to share requirements (a common interface IProjectile) between small arms and heavier weapons, or between lethal and non-lethal weapons, while implementing the three categories on three distinct abstract classes (LethalSmallArms, NonLethalSmallArms, and Howitzers) that all implement the common interface IProjectile.

Pieter Geerkens
  • 11,775
  • 2
  • 32
  • 52
  • 1
    I have been preferring this approach. Its bottom line would be: "for any given subclass, inherit contract from interface, and implementation from abstract base class, while both must be kept _independent_ from one another (even if semantically related)." – heltonbiker Mar 06 '15 at 12:42
4

I think you should go with the interface approach from Nathan's answer. But it is possible to declare abstract properties.

public abstract class Bullet
{
    public abstract int Damage { get; set; }
}

public class SomeBullet : Bullet
{
    public override int Damage { get; set; }  //This has to be implemented.
    ...
}
MAV
  • 7,260
  • 4
  • 30
  • 47
  • 4
    Note that it's even possible to omit the `set` requirement and have implementations return a fixed value. For example, `SomeBullet` might have: `public override int Damage { get { return 5; } }` – Chris Sinclair Apr 27 '13 at 02:05