我有一个非基本对象的arraylist,其中每个对象都是10个不同类之一的实例化。
我想遍历列表,并且列表中的每个对象都会调用基于对象类的方法。
通过帖子后,我看到了使用强制转换的建议; if / else;和有效的instanceof。 然而,我有很多课程,我想知道是否有更优雅 并简洁解决方案。
任何意见都赞赏。
答案 0 :(得分:7)
我确实避免了这种instanceof
- 支票链。事实上,我一般会避免使用if
/ else
或switch
链(例外情况适用)。
如果我们有一系列instanceof
检查,我们经常拥有的是错误的责任和缺乏多态性。
想象一下以下代码:
class Type1 {}
class Type2 {}
class Type3 {}
class TypeProcessor {
public void processObjets() {
final List<Object> objects = getObjectList();
for (final Object o : objects) {
if (o instanceof Type1) {
processType1((Type1) o);
} else if (o instanceof Type2) {
processType2((Type2) o);
} else if (o instanceof Type2) {
processType2((Type2) o);
}
}
}
public void processType1(final Type1 o) {
/* Process for Type 1. */
}
public void processType2(final Type2 o) {
/* Process for Type 2. */
}
public void processType3(final Type3 o) {
/* Process for Type 3. */
}
}
这可以像这样重构:
interface Type {
void process();
}
class Type1 implements Type {
public void process() {
/* Process for Type 1. */
}
}
class Type2 implements Type {
public void process() {
/* Process for Type 2. */
}
}
class Type3 implements Type {
public void process() {
/* Process for Type 3. */
}
}
class TypeProcessor {
public void processObjects() {
final List<Type> objects = getObjectList();
for (final Type o : objects) {
o.process();
}
}
}
答案 1 :(得分:0)
还有另一种继承方法。你可以让所有类扩展一个Parent类,如下所示,因为你的类没有扩展其他任何东西:
public class Parent{
public void doSomething(){
//do generic stuff here
}
}
然后根据需要在子类中覆盖它:
public class Child extends Parent{
public void doSomething(){
//do child specific if needed else don't redefine if Parent method is okay for the child.
}
}
一旦所有列表项都扩展了这个类,每个列表项都可以调用doSomething()来完成这项工作。 (迭代父项的集合。)
答案 2 :(得分:0)
我在Java中最常用于此类调度的方法是将类名映射到各自的处理程序。
Base Handler(根据您的需要可以是类或接口):
interface Handler {
// Can have a return value if you need it
public void handle(Object k);
}
字符串的示例实现:
class StringHandler implements Handler {
public void handle(Object k) {
if (!(k instanceof String))
throw new RuntimeException("You messed up your dispatcher!!!");
String string = (String) k;
System.out.println(string);
}
}
// During initialization, wire up the dispatcher
Map<String, Handler> dispatcher = new HashMap<>{{
put("classname", new HandlerForClassName());
// more mappings...
}};
// Later
List<Object> objects = new ArrayList<>(); // Whatever you're trying to loop over
for (Object k : objects)
if (k != null)
dispatcher.get(k.getClass()).handle(k);
要解释最后一行,您要使用调度程序查找k
的类名,以获取您将其连接到的处理程序。然后你在那个处理程序上调用handle(Object)
并传递它k
。如果您将String
连接到StringHandler
并且k
是一个字符串,则k
的值将打印到stdout。
实际上关心将对象分派给其处理程序的代码永远不必更改以容纳更多处理程序/对象类型。
请注意,双括号初始化的所有注意事项都适用于此处。简短的版本是不会无缘无故地传递它。或者你可以做很多事情。
另请注意,这种运行时调度具有很大的灵活性,包括即时修改。
// You can do this at any time
dispatcher.put("classname", new DifferentDispatcher());