2015-05-03 4 views
1

Я пытаюсь удалить избыточность, которую у меня есть в моих Enemy0, Enemy1, ... классах, которые наследуются от моего класса abstract Enemy. Это все Monogame/XNA.Как абстрагироваться или удалять избыточные методы в следующем примере класса

Моего абстрактный класс выглядит так:

public abstract class Enemy 
{ 
    public abstract Vector2 Position { get; } 

    public Enemy() {} 

    public abstract void Update(GameTime gameTime); 

    public abstract void Draw(SpriteBatch spriteBatch); 

    public abstract Part getLeftPart(); 

    public abstract Part getRightPart(); 

    public abstract Part getLeftLeftPart(); //This method only used in Boss0 classes 

    public abstract Part getRightRightPart(); //This method only used in Boss0 classes 
} 

Хотя мои Enemy# классов различаются по реализации, некоторые методы точно так же/избыточными и занимают комнату (но есть параметры, относящиеся к этому классу, например, частным переменная _leftPartPos).

Проблема возникает, когда у меня есть 20 или около Enemy# классов, и я решил добавить дополнительный параметр в Part объекта (который используется в getLeftPart() - я бы также изменить 20 из тех классов, которые наследуют Enemy

public class Enemy0 : Enemy 
{ 
    private Texture2D _partTexture; 
    private Vector2 _leftpartPos; 
    private Vector2 _rightPartPos; 

    public override Vector2 Position 
    { 
     get { return _position; } // Reason for this get is to access inner variables 
    }        // like _position.X = 10 
    private Vector2 _position; 

    public Enemy() {} 

    public abstract void Update(GameTime gameTime) 
    { 
     // Some varying functionality per inheriting class 
    } 

    public abstract void Draw(SpriteBatch spriteBatch) 
    { 
     // Some varying functionality per inheriting class 
    } 

    public override Part getLeftPart() // This always returns the same object (with 
    {         // different params) 
     return new Part(
      _partTexture, 
      _leftPartPos, 
      SpriteEffects.FlipHorizontally); 
    } 

    public abstract Part getRightPart() 
    { 
     return new Part(
      _partTexture, 
      _rightPartPos, 
      SpriteEffects.None); 
    } 

    public override Part getLeftLeftPart() 
    { 
     return null; // This only returns an instance in Boss0, Boss1, etc 
    } 

    public override Part getRightRightPart() 
    { 
     return null; 
    } 
} 

причина у меня есть это абстрактный класс, так что я могу инициализировать List<Enemy> объект и получить доступ к его разнообразным методам без необходимости преобразуйте каждый класс как Enemy0, Enemy1 ...

Есть ли способ, который я могу использовать в функциональности getLeftPart(), getRightPart(), ... в моем абстрактном классе? Есть ли лучший подход для всего этого?

+0

** TIP **: Подумайте о переименовании 'Enemy0' и' Enemy1', чтобы они были понятны. _ «20 или около того, врагов # классов» особенно плохо. Откуда вы знаете, что каждый делает? – MickyD

+0

Спасибо за подсказку, это пригодится! - В настоящее время я просто описываю каждый класс в '

', дополнительно включающий' 'фразы в конструкторе' ' –

ответ

1

Объявление их virtual вместо abstract. Таким образом, вы можете обеспечить базовую реализацию в корневом классе и переопределить ее в дочерних классах, если они требуют различной функциональности.

public abstract class RootClass 
{ 
    public virtual void DoSomething() 
    { 
     Console.WriteLine("I'm doing something in the root class"); 
    } 
} 

public class ChildClass1 : RootClass 
{ 
    public void SomethingElse() 
    { 
     DoSomething(); //Prints out "I'm doing something in the root class" 
    } 
} 

public class ChildClass2 : RootClass 
{ 
    public void SomethingElse() 
    { 
     DoSomething(); //Prints out "I'm doing something in ChildClass2 
    } 

    public override void DoSomething() 
    { 
     Console.WriteLine("I'm doing something in ChildClass2"); 
    } 
} 

Если вы должны принять переменное количество параметров, объявить метод с атрибутом params, как:

public virtual void DoSomething(params object[] args)

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

public virtual void DoSomething<T>(params T[] args)

Но разница лишь в том, что все параметры должны быть того же типа, или конвертированы к этому типу. Если вам нужен только один параметр некоторого типа, используйте:

public virtual void DoSomething<T>(T arg)

или вы можете иметь два (или несколько типов)

public virtual void DoSomething<T1, T2>(T1 arg1, T2 arg2)

и т.д., и т.д.

+0

Это очень помогло! Является ли более эффективным, если я определяю '_partTexture',' _leftpartPos' в моем абстрактном классе (как «защищенные» сеттеры/геттеры)?Таким образом, я могу переместить все функции 'getLeftPart()' и т. Д. В мой абстрактный класс как виртуальные и изменить их в моем классе наследования. Или я делаю что-то совершенно неправильное –

+1

Вы можете определить виртуальные геттеры/сеттеры (вы, вероятно, захотите создать их как свойства). это не очень эффективно, поскольку использует свойства, так как компилятор в любом случае делает методы get/set для них. Что касается наличия кода в базовом классе, то он также не более эффективен, кроме как с точки зрения обслуживания кода, но все же разумная вещь. –

Смежные вопросы