Empty methods in base class versus explicit type checking

Let's say you have two types of objects, one of which comes from the other, but adds one piece of additional functionality. Two ways I can think of dealing with this extra functionality are to add an empty method to the base class, which is always called (a derived class can override this method) or explicit type checking to see if you an instance of a derived class and then calling an additional method.

Both of them seem to be hacks, is there a better way? If not, is it preferable to another? Both methods will work, but do not seem particularly clean, since you pollute the base class with useless method stubs, otherwise you use explicit type checking, which is usually considered a bad idea.

Here is an example to understand what I mean:

public class Weapon { // Should there be an empty StartCharging() here? public virtual void Fire() { // Do something } } public class ChargedWeapon : Weapon { public void StartCharging() { // Do something } public override void Fire() { // Do something base.Fire(); } } public class Game { private Weapon weapon; public void HandleUserInput() { if (MouseButton.WasPressed()) { // Or should there be an if (weapon is ChargedWeapon) here weapon.StartCharging(); } else if (MouseButton.WasReleased()) { weapon.Fire(); } } } 
+4
source share
4 answers

It is better to add a method to the base class instead of type checking. What happens if you perform a type check and then decide to use a new type of weapon that also requires charging? Will you add another test condition?

Edit: in your code, I see the beginning of the implementation of the Strategy Pattern . I assume that your use case will greatly benefit from it and from the State Pattern . If you need more information about this, leave a comment (as they are slightly different from the original point of view)

+2
source

Definitely do not do Type Checking here.

The big question is why are you dealing with the Weapon type and then calling StartCharging on it in your Game class? This code assumes that all tools implement StartCharging - if they do not, then you have already disagreed with good OO practices.

Instead, I would create an abstract method like Initialise for a weapon. - In your Concrete Weapon classes, implement this in different ways - for example. for ChargedWeapon you should use:

  public override void Initialise() { StartCharging(); } 

for different weapons, the implementation will be different, for example. With a HolsteredWeapon it could be:

  public override void Initialise() { DrawWeapon(); } 

In this example, only the ChargedWeapon classes should contain the StartCharging() method, and only the HolsteredWeapon classes should contain the DrawWeapon() method. However, each weapon needs an Initialise method.

Now the base type contains only methods that apply to all specific implementations, so again we follow the good principles of OO.

+1
source

IMHO, it is better to allow the weapon (class) to process its own logic without exposing most of its internal structures.

So just add two methods, for example, with the pattern startAction()/stopAction() in this case startFiring()/stopFiring() , and the weapon decides whether it needs to first charge / fire one shot / fire / continuous fire ...

0
source

Best to do:

 public interface IChargable { void StartCharging(); } public interface IWeapon { void Fire(); } public class Weapon : IWeapon { public void Fire() { } } public class ChargedWeapon : Weapon, IChargable { public void StartCharging () { } } private Weapon weapon; public void HandleUserInput() { if (MouseButton.WasPressed() && weapon is IChargable) { ((IChargable)weapon).StartCharging(); } else if (MouseButton.WasReleased()) { weapon.Fire(); } } 

Edit: Suppose you need to add a new weapon that is not payable, for example, " ExtraWeapon , SupperWeapon ", then you can see that using this empty " StartCharging " method for all weapons that are not supported, it is useless and poor design in addition, you may have other methods or properties to set in these new types when MouseButton ... so type checking and using its preparation methods / properties is the best choice.

-1
source

All Articles