在没有 instanceof 的情况下使用由超类集合的子类实现的接口
Using interface implemented by subclass from a superclass collection without instanceof
我正在编写一个 2D 小游戏,所有游戏元素都是 GameObject 的子class。 class 游戏有一个 GameObject 集合。我的问题是,当玩家执行一个动作时,我通过 GameObject 的集合来找到玩家面前的东西,然后我只想使用由 GameObject 的 subclasses 实现的接口方法而不使用instanceof 和铸造。
Here is a (very) simplified class-diagram of the situation
我试图实现访问者模式,但我希望函数 visit()
将 Activable
或 Obstacle
作为参数而不是 TV
或Wall
.
这是一个代码示例:
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
...
}
电视:
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() {
...
}
...
}
我该如何解决这个问题?
与其在 GameObject
中为 watchTV()
或 hitWall()
创建所有这些单独的方法,不如在 GameObject
Abstract
中使用任何公共变量( name
、activatable
、obstacle
等)与一个名为 doButtonOneActivity()
.
的 Abstract
方法
然后制作您的其他对象,如 TV
或 Wall
,扩展 GameObject
并覆盖 doButtonOneActivity()
方法,无论单击时该特定项目会做什么。
现在您的 Game
class 只需在 GameObject
上调用 doButtonOneActivity()
对象本身就会知道它需要做什么,而无需您手动做到这一点。
希望对您有所帮助!
游戏:
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。
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;
}
}
电视,它扩展了GameObject并填充了它需要的方法。
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());
}
}
Wall,它扩展了GameObject并填充了它需要的方法。
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());
}
}
我认为很难找到一个问题的唯一答案。它涉及到设计和意图,并且总是需要权衡 space,很少有明确的答案。
不过我觉得你应该看看Composite Pattern。复合模式本质上采用一组不同的对象,并以相同的方式对待它们。它通过在所有更高级别的对象 Component 上实现所有接口来实现这一点,以便所有对象都继承一组通用的方法和属性。
在您的示例中,您可以将 GameObject
定义为您的组件,并实现 Obstacle
和 Activatable
接口。还要添加一些辅助方法,例如 isObstacle
和 isActivatable
,这样您就可以在不强制转换的情况下进行测试。现在您可以让访问者遍历列表并且只对某些对象执行操作,这就是我认为您所追求的。
我正在编写一个 2D 小游戏,所有游戏元素都是 GameObject 的子class。 class 游戏有一个 GameObject 集合。我的问题是,当玩家执行一个动作时,我通过 GameObject 的集合来找到玩家面前的东西,然后我只想使用由 GameObject 的 subclasses 实现的接口方法而不使用instanceof 和铸造。
Here is a (very) simplified class-diagram of the situation
我试图实现访问者模式,但我希望函数 visit()
将 Activable
或 Obstacle
作为参数而不是 TV
或Wall
.
这是一个代码示例:
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
...
}
电视:
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() {
...
}
...
}
我该如何解决这个问题?
与其在 GameObject
中为 watchTV()
或 hitWall()
创建所有这些单独的方法,不如在 GameObject
Abstract
中使用任何公共变量( name
、activatable
、obstacle
等)与一个名为 doButtonOneActivity()
.
Abstract
方法
然后制作您的其他对象,如 TV
或 Wall
,扩展 GameObject
并覆盖 doButtonOneActivity()
方法,无论单击时该特定项目会做什么。
现在您的 Game
class 只需在 GameObject
上调用 doButtonOneActivity()
对象本身就会知道它需要做什么,而无需您手动做到这一点。
希望对您有所帮助!
游戏:
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。
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;
}
}
电视,它扩展了GameObject并填充了它需要的方法。
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());
}
}
Wall,它扩展了GameObject并填充了它需要的方法。
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());
}
}
我认为很难找到一个问题的唯一答案。它涉及到设计和意图,并且总是需要权衡 space,很少有明确的答案。
不过我觉得你应该看看Composite Pattern。复合模式本质上采用一组不同的对象,并以相同的方式对待它们。它通过在所有更高级别的对象 Component 上实现所有接口来实现这一点,以便所有对象都继承一组通用的方法和属性。
在您的示例中,您可以将 GameObject
定义为您的组件,并实现 Obstacle
和 Activatable
接口。还要添加一些辅助方法,例如 isObstacle
和 isActivatable
,这样您就可以在不强制转换的情况下进行测试。现在您可以让访问者遍历列表并且只对某些对象执行操作,这就是我认为您所追求的。