开发者

Empty methods on base class vs explicit type checking

开发者 https://www.devze.com 2023-03-21 09:02 出处:网络
Let\'开发者_JAVA百科s say you have two types of object, one that derives from the other but adds a single piece of extra functionality. The two ways I can think to deal with this extra functionality a

Let'开发者_JAVA百科s say you have two types of object, one that derives from the other but adds a single piece of extra functionality. The two ways I can think to deal with this extra functionality are adding an empty method on the base class that is always called (the derived class can then override this method) or explicit type checking to see if you have an instance of the derived class and then calling the extra method.

Both of these seem like hacks, is there a better way? If not is one preferred over the other? Both ways would work but neither seems particularly clean, one way you are polluting the base class with useless method stubs, the other way you are using explicit type checking which is usually considered a bad idea.

Here's an example to make it clear 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();
        }
    }
}


It's better to add the method to base class instead of doing a type check. What will happen if you do a typecheck and then decide to implement a new type of weapon which also needs charging? Will you add another test condition?

Edit: In your code, I see a start for an implementation of Strategy Pattern. I guess that your use case will benefit greatly from it and from State Pattern. If you need more details on these, leave a comment (as they are a little offtopic from the initial question's point of view)


Definitely don't do Type Checking here.

The big question is why you are dealing with a type Weapon and then calling StartCharging on it in your Game class? The implication in this code is that all Weapons implement StartCharging - if they do not, then you have already diverged from good OO practices.

Instead of this I would create an abstract method such as Initialise on Weapon. - In your Concrete Weapon classes implement this in different ways - e.g. for ChargedWeapon you would use:

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

for different weapons, the implementation would differ, e.g. For a HolsteredWeapon it might be:

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

In these example, only ChargedWeapon classes need to contain a StartCharging() method, and only HolsteredWeapon classes need to contain a DrawWeapon() method. However, every weapon needs an Initialise method.

Now the base type only contains methods which apply to ALL concrete implementations, so we are once again following good OO principles.


IMHO it is better to let the weapon(class) handle its own logic without exposing to much of its internal designs.

So simply add two methods like with the pattern startAction()/stopAction() in this case startFiring()/stopFiring() and the weapons decides if it needs to charge first/fire a single shot/fire burst/continuous fire...


Better way is 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 weapons that is not chargeable too like "ExtraWeapon, SupperWeapon" , then you can see that using that empty method "StartCharging" for all the weapons that is not support it is useless and a bad design, furthermore you may have other methods or properties to set in that new types when MouseButton... so checking the type and only use its prepare methods/properties is a better choice.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号