Пустые методы в базовом классе против явной проверки типов - PullRequest
4 голосов
/ 20 июля 2011

Допустим, у вас есть два типа объектов, один из которых является производным от другого, но добавляет одну дополнительную функциональность. Я могу подумать, что есть два способа справиться с этой дополнительной функциональностью: добавить пустой метод в базовый класс, который всегда вызывается (производный класс может затем переопределить этот метод), или явную проверку типа, чтобы определить, есть ли у вас экземпляр производного класса. а затем вызов дополнительного метода.

Оба они кажутся хаки, есть ли лучший способ? Если нет, то один предпочтительнее другого? Оба способа сработают, но ни один из них не выглядит особенно чистым: один способ загрязнения базового класса бесполезными заглушками методов, другой способ использования явной проверки типов, что обычно считается плохой идеей.

Вот пример, чтобы прояснить, что я имею в виду:

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 ]

2 голосов
/ 20 июля 2011

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

Редактировать: в вашем коде я вижу начало реализации шаблона стратегии .Я полагаю, что ваш вариант использования сильно выиграет от этого и от State Pattern .Если вам нужно больше подробностей, оставьте комментарий (так как они немного оффтопичны с точки зрения первоначального вопроса)

1 голос
/ 20 июля 2011

Определенно не проверяйте тип здесь.

Большой вопрос: почему вы имеете дело с типом Weapon, а затем вызываете StartCharging в своем классе Game? Подразумевается, что в этом коде все Оружие реализуют StartCharging - если они этого не делают, то вы уже отошли от хороших ООП.

Вместо этого я бы создал абстрактный метод, такой как Initialise для оружия. - В ваших классах Бетонного оружия это реализуется по-разному, например для ChargedWeapon вы бы использовали:

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

для разных видов оружия, реализация будет отличаться, например, Для HolsteredWeapon это может быть:

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

В этом примере только классы ChargedWeapon должны содержать метод StartCharging(), и только классы HolsteredWeapon должны содержать метод DrawWeapon(). Однако каждому оружию нужен метод Initialise.

Теперь базовый тип содержит только методы, которые применяются ко ВСЕМ конкретным реализациям, поэтому мы снова следуем хорошим принципам ОО.

0 голосов
/ 20 июля 2011

Лучший способ сделать это:

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

Редактировать: Предположим, вам нужно добавить новое оружие, которое не подлежит оплате, например "ExtraWeapon, SupperWeapon",тогда вы можете видеть, что использование этого пустого метода "StartCharging" для всего оружия, которое не поддерживает, бесполезно и плохой дизайн, более того, у вас могут быть другие методы или свойства для установки в этих новых типахкогда MouseButton ... так что проверка типа и использование только его методов / свойств подготовки - лучший выбор.

0 голосов
/ 20 июля 2011

ИМХО, лучше, чтобы оружие (класс) обрабатывало свою собственную логику, не подвергая большей части своих внутренних замыслов.

Так что просто добавьте два метода, например, с шаблоном startAction()/stopAction(), в данном случае startFiring()/stopFiring(), и оружие решит, нужно ли ему сначала заряжать / выстрелить один раз / выстрел / непрерывный огонь ...

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