Есть ли лучший способ фильтрации типов объектов, которые могут быть переданы в конструктор наследуемого класса? - PullRequest
2 голосов
/ 13 июля 2010

Я знаю, что название немного многословно, но я не знаю, как еще задать этот вопрос. Это в основном техника, которую я использовал для фильтрации типов объектов, которые вы передаете в унаследованный класс. Посмотрите сначала на код, и я объясню больше ...

public interface IProjectile {}
public interface IPaintBall : IProjectile {}
public interface IPotato : IProjectile {}

public class Prop
{
    public void Shoot(params IProjectile[] projectiles)
    {
        // logic goes here...
    }
}

public class Car : Prop
{
    public override void Shoot(params IPaintBalls[] paintBalls)
    {
        base.Shoot(paintBalls);
    }
}

См? Я не хочу, чтобы ты застрелил мою машину картошкой. Вы можете стрелять в него только шариками с краской. Так я делаю это правильно? Опять же, это становится намного сложнее, когда класс Prop имеет около 100 функций, которые я также хочу отфильтровать до рисования. Я не хочу выписывать эти 100+ функций для класса Car, верно? Я особенно не хочу выписывать те 100+ функций для 100+ Car классов, которые я буду писать.

Я достаточно ясно здесь?

Это всего лишь пример. Я не занимаюсь программированием игр или чем-то в этом роде. Я просто пытаюсь дать вам очень простой пример, чтобы передать то, что я хочу здесь. По сути, я не хочу, чтобы код компилировался, если кто-то пытается передать картошку функции Shoot().

Ответы [ 5 ]

7 голосов
/ 13 июля 2010

То, что я, вероятно, сделал бы, чтобы заставить Опору принять Общий Тип. То есть:

public class Prop<T> where T : IProjectile
{
    public virtual void Shoot(params T[] projectiles)
    {
        // logic goes here... 
    }
}

public class Car : Prop<IPaintBall>
{
    public override void Shoot(params IPaintBall[] projectiles)
    {
        base.Shoot(projectiles);
    }
} 

Методы затем представляются как PaintBalls для пользователей класса Car, т.е.:

Car car = new Car();
car.Shoot(somePaintballs); // Shoot will only take IPaintBall.

Вы также можете иметь не общий класс Проп:

public class Prop : Prop<IProjectile>
{
}

Где вы все еще можете использовать:

public class Person : Prop
{
}

Person может быть застрелен любым IProjectile, включая IPotato.

1 голос
/ 13 июля 2010

Если я правильно понимаю, я бы пошел на дженерики:

public interface IProjectile { }
public interface IPaintBall : IProjectile { }
public interface IPotato : IProjectile { }

public abstract class Prop<TProjectile> where TProjectile : IProjectile
{
    public void Shoot(params TProjectile[] projectiles)
    {

    }
}

public class Car : Prop<IPaintBall>
{

}

class Program
{
    static void Main(string[] args)
    {
        Car myCar = new Car();

        IPaintBall[] paintballs = PaintBallFactory.GetPaintBalls();

        myCar.Shoot(paintballs);
    }
}

Тогда вы не можете позвонить в Car.Shoot только с шарами.

1 голос
/ 13 июля 2010

Это выглядит нормально для меня.Важно, что вы использовали интерфейсы, чтобы абстрагировать реализацию шара от краски.

Однако ваш код немного не в порядке:

public override void Shoot(params IPaintBall[] paintBalls)
{
    base.Shoot(paintBalls);
}

Обновление: в этомВ этом случае сделайте базовый класс защищенным и предоставьте новый метод для производного класса, но используйте базовую реализацию.

public class Prop
{
    protected void Shoot(params IProjectile[] projectiles)
    {
        // logic goes here...  
    }
}

public class Car : Prop
{
    public void Shoot(params IPaintBall[] projectiles)
    {
        base.Shoot(projectiles);
    }
}  

Не проверено в компиляторе, но я считаю, что базовые массивы ([]) являются ко-вариантами.

Обновление 2: В качестве альтернативы, определитеинтерфейс, отвечающий за съемку и предоставляющий ему метод Shoot.

public interface IProjectile { }
    public interface IPaintBall : IProjectile { }
    public interface IPotato : IProjectile { }
    public interface IShoot<T> where T : IProjectile
    {
        void Shoot(params T[] projectiles);
    }

    public interface IShootPaintBalls : IShoot<IPaintBall> { }

    public class Prop : IShoot<IProjectile>
    {
        public void  Shoot(params IProjectile[] projectiles)
        {
          // logic
        }
    }

    public class Car : Prop, IShootPaintBalls
    {
        public void  Shoot(params IPaintBall[] projectiles)
        {
            base.Shoot(projectiles);
        }
    }

Обновление 3: Ответ GenericTypeTea завершает круг обобщений :-), мое текущее решение не мешает вам сниматьмашина с картошкой ...

0 голосов
/ 13 июля 2010

Вы не можете сделать это чисто во время компиляции в .NET.Чтобы реализовать интерфейс, вы должны реализовать все его методы.

Но явная реализация интерфейса позволит вам в некоторой степени скрыть унаследованный метод IProjectile, предоставляя общедоступные IPaintBalls методы.

Но там Prop не делает Shoot виртуальным, поэтому вы все равно не сможете его переопределить.И Prop - это класс, интерфейс к которому явная реализация неприменима.

Кажется, вам потребуется:

  1. Сделать Prop.Shoot виртуальным и
  2. Принять проверку во время выполнения.

Примерно так:

public class Prop {
  public virtual void Shoot(params IProjectile[] projectiles) {
    ...
  }
}

public class Car : Prop {
  public override void Shoot(params IProjectile[] projectiles) {
    foreach (var p in projectiles) {
      if (!(p is IPaintBall)) {
        throw new ArgumentException("Only shoot cars with paint balls");
      }
    }
    Shoot(projectiles.Cast<IPaintBall>().ToArray());
  }

  public virtual void Shoot(params IPaintBall[] balls) {
    // Allow callers that are calling with paint balls (know at compile time)
    // to come in directly.
  }
}
0 голосов
/ 13 июля 2010

Создайте больше интерфейсов, в этом случае IShootableProjectile, который наследует IProjectile.То же самое касается Prop, это слишком общий класс.

Не создавайте интерфейсы или классы, которые могут делать много разных вещей.Разбейте их на небольшие группы, покрывающие определенную ответственность.Узнайте больше о следующих принципах проектирования:

http://blog.gauffin.org/2010/06/hello-world/

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