Возвращение расширенного класса, где ожидается суперкласс - PullRequest
2 голосов
/ 13 декабря 2011

В настоящее время я работаю над игрой, использующей Pattern Component Pattern , и всегда задавался вопросом, как это сделать.У меня есть сущность, которая представляет собой просто набор компонентов.Каждый компонент расширяет класс Component, который просто обладает некоторыми базовыми функциями.

Расширяя класс компонента, создаются новые компоненты для удобного ввода, графики и т. Д. Теперь возникает проблема;Когда я пытаюсь получить конкретный компонент от объекта, он всегда возвращает базовый класс Component, что не позволяет мне использовать определенные функции компонента.

    public class GameEntity
{
    private ArrayList<Component> components;

    public GameEntity()
    {
        components = new ArrayList<Component>();
    }

    public void addComponent(Component component)
    {
        components.add(component);
    }

    public void update()
    {

    }

   public Component getComponent(Class type)
   {
       for (Component component : components)
       {
            if(component.getClass() == type)
            {
                //return component as Class;

            }
       }
       return null;
   }


    public void draw(Canvas canvas)
    {
        for (Component component : components)
        {
            component.update();
            component.draw(canvas);
        }
    }

}

Некоторые примеры компонентов:

открытый класс GraphicsComponent extends Component {

public Bitmap bitmap;public Rect currentFrameRect;приватный ArrayList spriteAnimations;общедоступная SpriteAnimation currentAnimation;public int x = 0;public int y = 50;public GraphicsComponent () {spriteAnimations = new ArrayList ();}

/**
 * Adds image [converts to spriteanimation]
 * @param image
 */
public void addImage(Bitmap image, String label)
{
    Rect[] tmpRects = {new Rect(0, 0, image.getWidth(), image.getHeight())} ;
    addAnimation(new SpriteAnimation(
            image, tmpRects, label
    ));
}

public void addAnimation(SpriteAnimation spriteAnimation)
{
    spriteAnimations.add(spriteAnimation);

   if(currentAnimation == null)
   {
       currentAnimation = spriteAnimation;
   }
}


@Override
public void update()
{
   currentFrameRect = currentAnimation.frames[currentAnimation.currentFrame];
}

@ Переопределить public void draw (Canvas canvas) {

    if(currentAnimation != null)
    {
        currentAnimation.draw(x, y, canvas);
    }     }
public int getWidth()
{
    return currentAnimation.frames[currentAnimation.currentFrame].width();
}

public int getHeight()
{
    return currentAnimation.frames[currentAnimation.currentFrame].height();
}
}


public class InteractiveComponent extends Component
{
    public GraphicsComponent graphics;

    public InteractiveComponent(GraphicsComponent graphics)
    {
        this.graphics = graphics;
    }

    public boolean isOver(int tapX, int tapY)
    {
        //left top right bottom
        if(tapX > graphics.x && tapX < graphics.x + graphics.getWidth() &&
           tapY > graphics.y && tapY < graphics.y + graphics.getHeight()
        )
        {
            return true;
        }
        return false;
    }

}

Кажется, есть некоторые проблемы с форматированием кода, но это должно бытьЧисто.Я не могу получить доступ к каким-либо конкретным функциям, таким как getHeight () в graphicComponent или isOver () из interactiveComponent, потому что я просто возвращаю базовый компонент.

Я хотел бы вернуть GraphicsComponent или InteractiveComponent на основе класса, который я передаю в getComponent () .

Ответы [ 5 ]

3 голосов
/ 13 декабря 2011

То, что вы пытаетесь сделать, кажется мне архитектурно подозрительным, но, тем не менее, это можно сделать «чистым» способом с использованием обобщений, и вы уже передаете объект класса в качестве токена типа:

class Animals {
    List<Animal> animals = new ArrayList<Animal>();

    public <T extends Animal> T getAnimal(Class<T> type) {
        for (Animal animal : animals) {
            if (type.isAssignableFrom(animal.getClass())) {
                return type.cast(animal);
            }
        }
        return null;
    }
}

class Main {
    public static void main(String[] args) {
        Animals animals = new Animals();
        animals.getAnimal(Cat.class).meow();
        animals.getAnimal(Dog.class).bark();
    }
}

interface Animal {}

class Cat implements Animal {
    public void meow() {}
}

class Dog implements Animal {
    public void bark() {}
}

Вы можете == или equals() вместо проверки isAssignableFrom() в зависимости от желаемого поведения.

2 голосов
/ 13 декабря 2011

Другие предложили снизить рейтинг в качестве решения. Я бы сказал: Редизайн .

Если вам нужно понизить рейтинг, это означает, что у вас, вероятно, архитектурная проблема. И действительно, у вас есть. Вы хотите получить доступ к каждому объекту, но не полиморфным способом. Поэтому пытаться получить доступ к определенным объектам через контейнер супертипа неестественно / бесполезно / неэффективно.

Я бы предложил:

class GameEntity {
    private GraphicsComponent graphics;
    private InteractiveComponent interactive;
    private SoundComponent sound;

    private List<Component> components;

    public GameEntity() {
        components.add(graphics);
        // etc.
    }

    public GraphicsComponent getGraphics() { return graphics; }
    // etc.

    public void draw() {
        for (Component c : components) {
            ...
        }
    }
}
0 голосов
/ 13 декабря 2011

Ну, функция возвращает Component. Если вы знаете, что запросили определенный компонент, приведите результат:

GraphicsComponent gc = (GraphicsComponent)(gameEntityInstance.getComponent(GraphicsComponent.class));
0 голосов
/ 13 декабря 2011

Лучшей ставкой будет разыграть при вызове getComponent() и удалить аргумент Class из этого метода.

Таким образом, getComponent вернет Component, который может быть разыгран вInteractiveComponent или GraphicsComponent:

public Component getComponent() { /* its contents */ };

GraphicsComponent gc = (GraphicsComponent)...getComponent();
InteractiveComponent ic = (InteractiveComponent)...getComponent();
0 голосов
/ 13 декабря 2011

Как только вы получили компонент таким образом, вам пришлось бы привести его обратно к типу класса.Затем вы можете получить доступ к getHeight () и т. Д. Объект, как известно, не является графическим компонентом, но это так.

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