Java "instanceof" 添加多个列表
Java "instanceof" to add over multiple lists
在了解到实现优于扩展之后,我目前正在尝试重构我的代码。目前,我正在尝试创建一个将对象添加到场景中的函数。为了更好的定义每个对象是什么,有多个List比如一个list用于更新,渲染等
private List<Updatable> updatables;
private List<Removable> removables;
private List<Renderable> renderables;
private List<Collidable> collidables;
我想在我的场景中创建一个函数 class,如下所示:
public void add(Object o) {
if(o instanceof Updatable)
updatables.add((Updatable) o);
if(o instanceof Removable)
removables.add((Removable) o);
if(o instanceof Renderable)
renderables.add((Renderable) o);
if(o instanceof Collidable)
collidables.add((Collidable) o);
}
同样,我会创建一个类似的删除功能。我的问题是,这是否是糟糕的编码习惯,因为我听说过 instanceof 的缺陷,其次,如果是,是否有解决此问题/重组我的代码以使添加实例变得简单的方法?我不想每次都向每个列表添加一个实例并定义它属于哪个列表。
我会使用 Map
对工厂模式做类似的事情
static Map<String, List> maps = new HashMap<>();
static {
maps.put(Updatable.class.getName(), new ArrayList<Updatable>());
maps.put(Removable.class.getName(), new ArrayList<Removable>());
maps.put(Renderable.class.getName(), new ArrayList<Renderable>());
maps.put(Collidable.class.getName(), new ArrayList<Collidable>());
}
public static void add(Object obj){
maps.get(obj.getClass().getName()).add(obj);
}
只需使用重载:add(Updateable u), add(Removable r),
等
正如您在评论中提到的,您的用例有些特殊。 Updatable
、Removable
、Renderable
和 Collidable
都是 接口 。您有 类 实现了这些接口中的一个或多个。最终,您希望 add
方法将一个对象添加到它实现的接口的每个列表中。 (如果有任何错误,请纠正我。)
如果重载过于冗长,您可以通过反射来实现,如下所示:
private List<Updatable> updatables;
private List<Removable> removables;
private List<Renderable> renderables;
private List<Collidable> collidables;
@SuppressWarnings("unchecked")
public void add(Object o) {
try {
for (Class c : o.getClass().getInterfaces()) {
// Changes "Updatable" to "updatables", "Removable" to "removables", etc.
String listName = c.getSimpleName().toLowerCase() + "s";
// Adds o to the list named by listName.
((List) getClass().getDeclaredField(listName).get(this)).add(o);
}
} catch (IllegalAccessException e) {
// TODO Handle it
} catch (NoSuchFieldException e) {
// TODO Handle it
}
}
但是如果您打算使用这种方法,请注意以下注意事项:
- 反射本质上很容易出现 运行时间错误。
- 如果您的层次结构更复杂,您可能 运行 会遇到问题。例如,如果您有
Foo implements Updatable, Removable
和 Bar extends Foo
,那么在 Bar
上调用 getClass().getInterfaces()
将 return 一个空数组。如果这听起来像您的用例,您可能想改用 Apache Commons Lang 中的 ClassUtils.getAllInterfaces。
我希望您对每个列表都有一个单独的 add
方法,如下所示:
public void addUpdatable(Updatable updatable) {
updatables.add(updatable);
}
public void addRemovable(Removable removable) {
removables.add(removable);
}
// and so on
这样做的原因是这些是单独的列表,虽然从实现的角度来看,关注的是 API 优雅和圆滑,但从用户的角度来看,这些努力会对清晰度产生负面影响。
例如,关于添加 Updatable
也是 Removable
时会发生什么的误解(在 EJP 的回答评论中)表明这种不明确。尽管您对您的类型和您的状态使用了相似的术语,这使得它看起来多余,但您仍然应该明确将项目添加到哪个列表(或状态的一部分)。
无论如何,看起来你正在努力解决更大范围的问题。我认为花更多的时间来理解更大的问题是个好主意。
来自@Jerry06,对我来说,将实例添加到多个不同类型列表的最佳方法是使用魔术列表 getter。
private Map<Class, List> maps = new HashMap<>();
'maps' 用于查找您要查找的列表。
private <T> List<T> get(Class<T> c) {
return maps.get(c);
}
而不是使用 maps.get,我只是使用 get(SomeClass.class)。上面的函数自动将其转换为具有正确元素类型的列表。然后我能够做到:
get(Updatable.class).stream().filter(Updatable::isAwake).forEach(Updatable::update);
而不是:
updatables.stream().filter(Updatable::isAwake).forEach(Updatable::update);
我最想要的是这样的结构,这样所有的列表都可以很好地包装起来,其次我可以直接说 maps.add(SomeNewClass.class, new ArrayList()),然后调用它只要我想。
在了解到实现优于扩展之后,我目前正在尝试重构我的代码。目前,我正在尝试创建一个将对象添加到场景中的函数。为了更好的定义每个对象是什么,有多个List比如一个list用于更新,渲染等
private List<Updatable> updatables;
private List<Removable> removables;
private List<Renderable> renderables;
private List<Collidable> collidables;
我想在我的场景中创建一个函数 class,如下所示:
public void add(Object o) {
if(o instanceof Updatable)
updatables.add((Updatable) o);
if(o instanceof Removable)
removables.add((Removable) o);
if(o instanceof Renderable)
renderables.add((Renderable) o);
if(o instanceof Collidable)
collidables.add((Collidable) o);
}
同样,我会创建一个类似的删除功能。我的问题是,这是否是糟糕的编码习惯,因为我听说过 instanceof 的缺陷,其次,如果是,是否有解决此问题/重组我的代码以使添加实例变得简单的方法?我不想每次都向每个列表添加一个实例并定义它属于哪个列表。
我会使用 Map
static Map<String, List> maps = new HashMap<>();
static {
maps.put(Updatable.class.getName(), new ArrayList<Updatable>());
maps.put(Removable.class.getName(), new ArrayList<Removable>());
maps.put(Renderable.class.getName(), new ArrayList<Renderable>());
maps.put(Collidable.class.getName(), new ArrayList<Collidable>());
}
public static void add(Object obj){
maps.get(obj.getClass().getName()).add(obj);
}
只需使用重载:add(Updateable u), add(Removable r),
等
正如您在评论中提到的,您的用例有些特殊。 Updatable
、Removable
、Renderable
和 Collidable
都是 接口 。您有 类 实现了这些接口中的一个或多个。最终,您希望 add
方法将一个对象添加到它实现的接口的每个列表中。 (如果有任何错误,请纠正我。)
如果重载过于冗长,您可以通过反射来实现,如下所示:
private List<Updatable> updatables;
private List<Removable> removables;
private List<Renderable> renderables;
private List<Collidable> collidables;
@SuppressWarnings("unchecked")
public void add(Object o) {
try {
for (Class c : o.getClass().getInterfaces()) {
// Changes "Updatable" to "updatables", "Removable" to "removables", etc.
String listName = c.getSimpleName().toLowerCase() + "s";
// Adds o to the list named by listName.
((List) getClass().getDeclaredField(listName).get(this)).add(o);
}
} catch (IllegalAccessException e) {
// TODO Handle it
} catch (NoSuchFieldException e) {
// TODO Handle it
}
}
但是如果您打算使用这种方法,请注意以下注意事项:
- 反射本质上很容易出现 运行时间错误。
- 如果您的层次结构更复杂,您可能 运行 会遇到问题。例如,如果您有
Foo implements Updatable, Removable
和Bar extends Foo
,那么在Bar
上调用getClass().getInterfaces()
将 return 一个空数组。如果这听起来像您的用例,您可能想改用 Apache Commons Lang 中的 ClassUtils.getAllInterfaces。
我希望您对每个列表都有一个单独的 add
方法,如下所示:
public void addUpdatable(Updatable updatable) {
updatables.add(updatable);
}
public void addRemovable(Removable removable) {
removables.add(removable);
}
// and so on
这样做的原因是这些是单独的列表,虽然从实现的角度来看,关注的是 API 优雅和圆滑,但从用户的角度来看,这些努力会对清晰度产生负面影响。
例如,关于添加 Updatable
也是 Removable
时会发生什么的误解(在 EJP 的回答评论中)表明这种不明确。尽管您对您的类型和您的状态使用了相似的术语,这使得它看起来多余,但您仍然应该明确将项目添加到哪个列表(或状态的一部分)。
无论如何,看起来你正在努力解决更大范围的问题。我认为花更多的时间来理解更大的问题是个好主意。
来自@Jerry06,对我来说,将实例添加到多个不同类型列表的最佳方法是使用魔术列表 getter。
private Map<Class, List> maps = new HashMap<>();
'maps' 用于查找您要查找的列表。
private <T> List<T> get(Class<T> c) {
return maps.get(c);
}
而不是使用 maps.get,我只是使用 get(SomeClass.class)。上面的函数自动将其转换为具有正确元素类型的列表。然后我能够做到:
get(Updatable.class).stream().filter(Updatable::isAwake).forEach(Updatable::update);
而不是:
updatables.stream().filter(Updatable::isAwake).forEach(Updatable::update);
我最想要的是这样的结构,这样所有的列表都可以很好地包装起来,其次我可以直接说 maps.add(SomeNewClass.class, new ArrayList()),然后调用它只要我想。