使用不带instanceof的超类集合中的子类实现的接口

时间:2019-04-12 15:39:00

标签: java interface subclass instanceof visitor

我正在编写一个2D游戏,所有游戏元素都是GameObject的子类。 Game类具有GameObject的集合。我的问题是,当玩家执行一个动作时,我会遍历GameObject的集合以查找玩家面前的内容,然后我只想使用由GameObject子类实现的接口的方法,而不使用instanceof和cast。 >

Here is a (very) simplified class-diagram of the situation

我尝试实现访客模式,但我希望函数visit()接受ActivableObstacle作为参数,而不接受TV或{{ 1}}。

下面是一个代码示例:

Wall

GameObject:

class Game {
    private ArrayList<GameObject> gameObjects;
    ...
    public void actionPerformed(...) {
        GameObject current;
        //find the focused Game object
        ...

        //What's easiest but I don't want
        if(gameObjects instanceOf Obstacle) {
            ((Obstacle) current).aMethod()
            ...
        } else if (gameObjects instanceOf Activable) {
            ((Activable) current).activate()
            ...
        }
        ...

        //What visitor allow me
        public void watchVisit(TV tv) {
            tv.watch();
        }
        public void hitVisit(Wall w) {
            //...
        }

        //What I want
        public void activableVisit(Activable a) {
            a.activate();
        }
        public void walkVisit(Obstacle o) {
            //...
        }
        ...
}

电视:

class GameObject {
    public void acceptWatch(Game g) {
        //Do nothing, only implemented in class TV
    }
    //Same with wall
    ...
}

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:0)

不是在watchTV()中为hitWall()GameObject制作所有这些单独的方法,而是在GameObject Abstract上加上任何公共变量({{ 1}},nameactivatable等)和一种称为obstacle的{​​{1}}方法。

然后使您的其他对象(例如AbstractdoButtonOneActivity()扩展TV并用单击该特定项目时所做的任何操作覆盖Wall方法。

现在,您的GameObject类可以只在doButtonOneActivity()上调用Game,对象本身可以弄清楚它需要做什么,而不必手动进行管理。

希望对您有帮助!

游戏:

doButtonOneActivity()

GameObject,它是Abstract。

GameObject

电视,它扩展了GameObject并填写了所需的方法。

public class Game implements Serializable, IClusterable {
    private static final long serialVersionUID = 1L;

    private ArrayList<GameObject> gameObjects;

    public void actionPerformed(GameObject current) {

        // Let the object do whatever it's supposed to do on button press, in either case.
        current.doButtonOneActivity();

        if(current.isActivatable()){
            // Do whatever extra thing you need to do if this one is Activatable...
            System.out.println("Hey, this thing is activatable!");
        } else if (current.isObstacle()){
            // Do something an obstacle needs you to do
            System.out.println("Hey, this thing is an obstacle!");
        }

    }
}

The Wall,它扩展了GameObject并填写了所需的方法。

public abstract class GameObject implements Serializable, IClusterable {
    private static final long serialVersionUID = 1L;

    public String name;
    private boolean activatable;
    private boolean obstacle;

    public GameObject(String name, boolean activatable, boolean obstacle) {
        super();
        this.name = name;
        this.activatable = activatable;
        this.obstacle = obstacle;
    }

    public abstract void doButtonOneActivity();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isActivatable() {
        return activatable;
    }

    public void setActivatable(boolean activatable) {
        this.activatable = activatable;
    }

    public boolean isObstacle() {
        return obstacle;
    }

    public void setObstacle(boolean obstacle) {
        this.obstacle = obstacle;
    }
}

答案 1 :(得分:0)

我认为很难找到您问题的一个答案。它涉及设计和意图,并且在该空间中总是存在折衷,很少有明确的答案。

但是我认为您应该看看Composite Pattern。合成模式本质上采用一组不同的对象,并以相同的方式对待它们。它是通过在所有更高级别的对象Component上实现所有接口来实现的,以便所有对象都继承一组通用的方法和属性。

在您的示例中,您可以将GameObject定义为组件,并同时实现ObstacleActivatable接口。还添加一些辅助方法,例如isObstacleisActivatable,以便您无需进行转换即可进行测试。现在,您可以让访问者浏览列表,并且只对某些对象执行操作,这正是我认为的目标。