首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用由超类集合中的子类实现的接口,而不使用instanceof

使用由超类集合中的子类实现的接口,而不使用instanceof
EN

Stack Overflow用户
提问于 2019-04-12 23:39:00
回答 2查看 58关注 0票数 1

我正在编写一个小2D游戏,所有的游戏元素都是GameObject的子类。类游戏有一个GameObject的集合。我的问题是,当播放器执行操作时,我会遍历GameObject的集合来查找播放器前面的内容,然后我只想使用由GameObject的子类实现的接口的方法,而不使用instanceof和强制转换。

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

我试图实现访问者模式,但我希望函数visit()接受ActivableObstacle作为参数,而不是TVWall

下面是一个代码示例:

代码语言:javascript
复制
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) {
            //...
        }
        ...
}

GameObject:

代码语言:javascript
复制
class GameObject {
    public void acceptWatch(Game g) {
        //Do nothing, only implemented in class TV
    }
    //Same with wall
    ...
}

电视:

代码语言:javascript
复制
class TV extends Item implements Activable {
    public void acceptWatch(Game g) {
        //this works if watchVisit take a "TV" but not if it's a "Activable"
        g.watchVisit(this);
    }
    public void watch() {
        ...
    }
    ...
}

我该如何解决这个问题?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-04-12 23:52:27

不是在GameObject中为watchTV()hitWall()创建所有这些单独的方法,而是使用一个名为< Abstract >D9Abstract>的代码方法来创建带有任何公共变量(nameactivatableobstacle等)的Abstract

然后,使您的其他对象(如TVWall )扩展GameObject,并使用该特定项在单击时将执行的操作覆盖doButtonOneActivity()方法。

现在,您的Game类只需在GameObject上调用doButtonOneActivity(),对象本身就会找出它需要做什么,而不必手动管理。

我希望这对你有帮助!

游戏:

代码语言:javascript
复制
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!");
        }

    }
}

GameObject是抽象的。

代码语言:javascript
复制
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;
    }
}

TV,它扩展了GameObject并填充了它需要的方法。

代码语言:javascript
复制
public class TV extends GameObject implements Serializable, IClusterable {
    private static final long serialVersionUID = 1L;

    public TV(String name, boolean activatable, boolean obstacle) {
        super(name, activatable, obstacle);
    }

    @Override
    public void doButtonOneActivity() {
        if(isActivatable()){
            // do whatever I need to do as a TV when I am activated...
           }
           if (isObstacle()){
            // do whatever I need to do as a TV when I am activated as an obstacle...
           }
           System.out.println("I'm a TV and I was called. My name is: " + getName()); 

    }
}

墙,它扩展了GameObject并填充了它需要的方法。

代码语言:javascript
复制
public class Wall extends GameObject implements Serializable, IClusterable {
    private static final long serialVersionUID = 1L;

    public Wall(String name, boolean activatable, boolean obstacle) {
        super(name, activatable, obstacle);
    }

    @Override
    public void doButtonOneActivity() {    
        if(isActivatable()){
         // do whatever I need to do as a Wall when I am activated...
        }
        if (isObstacle()){
         // do whatever I need to do as a Wall when I am activated as an obstacle...
        }
        System.out.println("I'm a wall and I was called. My name is: " + getName()); 

    }
}
票数 0
EN

Stack Overflow用户

发布于 2019-04-12 23:56:35

我想你的问题很难只找到一个答案。它涉及到设计和意图,在这个领域总是有权衡,很少有明确的答案。

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

在您的示例中,您可以将GameObject定义为您的组件,并实现ObstacleActivatable接口。还可以添加一些辅助方法,如isObstacleisActivatable,这样您就可以在不进行强制转换的情况下进行测试。现在你可以让访问者遍历列表,只对某些对象执行操作,这就是我认为你想要的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55655161

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档