【问题标题】:Returning an extended class where super class is expected返回期望超类的扩展类
【发布时间】:2012-01-18 22:41:29
【问题描述】:

我目前正在使用组件模式制作一款游戏,并且一直想知道这是如何做到的。 我有一个实体,它实际上只是一袋组件。每个组件都扩展了 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 扩展组件 {

公共位图位图; 公共矩形 currentFrameRect; 私有 ArrayList spriteAnimations; 公共 SpriteAnimation 当前动画;公共 int x = 0;公共 int y = 50;民众 图形组件(){ 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];
}

@Override 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;
    }

}

代码格式似乎有些问题,但应该很清楚。 我无法访问任何特定函数,例如graphicComponent 中的getHeight() 或interactiveComponent 中的isOver(),因为我只返回了一个基本组件。

我想根据传递给 getComponent() 的类返回一个 GraphicsComponentInteractiveComponent

【问题讨论】:

  • 向下转换到你想要的类。
  • 示例代码太多了。
  • 我不熟悉向下转换这个词,谢谢你提到它。我为冗长的代码道歉,我担心我的问题不够清楚。

标签: java class components


【解决方案1】:

您尝试做的事情在我看来在架构上是可疑的,但尽管如此,它可以使用泛型以“干净”的方式完成,并且您已经将类对象作为类型标记传递:

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() 检查,具体取决于您想要的确切行为。

【讨论】:

  • 一个Class&lt;T&gt; 参数和一个T 返回值是告诉编译器方法的返回类型取决于参数值的方式——这就是你可以说“返回这个类型”。
  • 在架构上,似乎你有一堆单例——通常只有一个类型的实例存在的对象。流行的处理方法是使用 IoC 容器和依赖注入,以避免编写一个带有许多管理这些 getter 的臃肿类。 IoC 容器存在的理由是以通用方式实现此模式。尝试查看GuiceSpring Framework
  • 我可能理解不正确,但可能有多个实体都有自己的组件。因此,可以有超过 1 个所述组件的实例。我将尝试查看框架,但老实说,这一切似乎都超出了我的水平:(我遇到了另一个问题:我扩展了 graphicsComponent,因此我可以设置一些简单的模板来使用,其中所有的动画已经预定义等。但是,由于它只检查它是否与 graphicsComponent 匹配,而不是它的任何超类,它返回一个 null :( 还有什么方法可以检查超类吗?
  • 实际上,我知道有一种方法可以检查所有超(基)类,但这似乎比我已经在做的更脏。你建议不同的方法吗?谢谢!
  • @omgnoseat 因此“似乎”。我真的不知道你的设计是什么,关于如何构建你的应用程序有无数种“好”的方法,每种方法都有自己的优缺点。
【解决方案2】:

其他人建议将向下转换作为解决方案。我会说:重新设计

如果您发现自己需要向下转型,则表明您可能遇到了架构问题。事实上,你有。您想访问每个对象,但不是以多态方式。因此,尝试通过超类型的容器访问特定对象是不自然/无用/低效的。

我建议:

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) {
            ...
        }
    }
}

【讨论】:

  • 虽然在这种情况下重新设计可能是合适的,但如果您需要向下转型,那么您就会遇到架构问题的说法肯定并非总是如此。
  • @increment:确实,这就是我说“指示”的原因;并非总是如此,但通常如此。
  • 您的编辑添加了 probably,这似乎更合适,但我什至会将其弱化为 may,但这可能只是意见。在您的重新架构建议中,您可能仍然需要解决组件看起来是动态的并且需要迭代以进行绘制/更新的问题。
  • @increment1:没错,我自己也在考虑这个问题。我想解决方案是将组件都存储为命名子类型,并存储在容器中
  • 会有很多组件,所以我的文件会被 getter 淹没。但它确实有效,感谢您的回复!
【解决方案3】:

一旦您以这种方式收到一个组件,您就必须将它转换回类类型。然后您可以访问 getHeight() 等。该对象根本不知道是图形组件,但它是。

【讨论】:

    【解决方案4】:

    好吧,该函数返回一个Component。如果您知道您已请求特定组件,请转换结果:

    GraphicsComponent gc = (GraphicsComponent)(gameEntityInstance.getComponent(GraphicsComponent.class));
    

    【讨论】:

      【解决方案5】:

      您最好的选择是在调用 getComponent() 并从该方法中删除 Class 参数时进行转换。

      所以,getComponent 将返回一个 Component,它可以转换为 InteractiveComponentGraphicsComponent

      public Component getComponent() { /* its contents */ };
      
      GraphicsComponent gc = (GraphicsComponent)...getComponent();
      InteractiveComponent ic = (InteractiveComponent)...getComponent();
      

      【讨论】:

      • 我有点不喜欢演员表,不知道为什么,但使用它们感觉很hacky。不过,这似乎是一个很好的解决方案,谢谢。
      • 我也有同感,但目前还没有找到更好的方法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-12
      • 1970-01-01
      • 1970-01-01
      • 2011-06-25
      • 2018-04-06
      • 1970-01-01
      相关资源
      最近更新 更多