基类和显式类型检查的空方法

时间:2011-07-20 09:02:52

标签: c# oop inheritance

假设您有两种类型的对象,一种是从另一种派生而来的,但却添加了一个额外的功能。我可以想到处理这个额外功能的两种方法是在基类上添加一个空方法,该方法总是被调用(派生类可以覆盖此方法)或显式类型检查以查看是否有派生类的实例然后调用额外的方法。

这些看起来都像黑客,有更好的方法吗?如果不是一个优先于另一个?两种方式都可以工作,但似乎都不是特别干净,一种方法是使用无用的方法存根来污染基类,另一种方法是使用显式类型检查,这通常被认为是一个坏主意。

这是一个清楚我的意思的例子:

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 个答案:

答案 0 :(得分:2)

最好将方法添加到基类,而不是进行类型检查。如果你做了一个类型检查,然后决定实施一种还需要充电的新型武器,会发生什么?你会增加另一个测试条件吗?

编辑:在您的代码中,我看到了Strategy Pattern实现的开始。我想你的用例将从State Pattern中受益匪浅。如果您需要更多关于这些的详细信息,请发表评论(因为它们与初始问题的观点相比有点偏离主题)

答案 1 :(得分:1)

绝对不要在这里进行类型检查。

最大的问题是,为什么要处理Weapon类型,然后在StartCharging类中调用Game?这段代码的含义是所有武器都实现了StartCharging - 如果它们没有,那么你已经偏离了良好的OO实践。

而不是这样,我会在武器上创建一个抽象方法,例如Initialise。 - 在你的混凝土武器类中以不同的方式实现它 - 例如对于ChargedWeapon你会使用:

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

对于不同的武器,实施方式会有所不同,例如:对于HolsteredWeapon,它可能是:

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

在这些示例中,只有ChargedWeapon个类需要包含StartCharging()方法,并且只有HolsteredWeapon个类需要包含DrawWeapon()方法。但是,每种武器都需要Initialise方法。

现在基类型只包含适用于所有具体实现的方法,因此我们再次遵循良好的OO原则。

答案 2 :(得分:0)

恕我直言,最好让武器(类)处理自己的逻辑而不暴露其大部分内部设计。

因此,简单地添加两种方法,例如在这种情况下使用模式startAction()/stopAction() startFiring()/stopFiring(),武器决定是否需要首先充电/发射一次射击/火焰爆发/持续射击... < / p>

答案 3 :(得分:-1)

更好的方法是:

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();
    }
}

修改:假设您需要添加一个不收费的新武器,例如“ExtraWeaponSupperWeapon”,那么您可以看到使用该方法“StartCharging”对于所有不支持它的武器都是无用的而且是一个糟糕的设计,此外,在MouseButton时,你可以在新类型中设置其他方法或属性。 ..所以检查类型并只使用其准备方法/属性是一个更好的选择。