在这种情况下替代instanceof方法

时间:2011-02-21 10:27:41

标签: java instanceof

您好我想知道这样的更优雅的替代品会是什么:

class Base...

class A extends Base...

class B extends Base...

//iterator of colection containing mixed As and Bs i want to remowe Bs and do omething with As
while(iterator.hasNext()) {
    Base next = iterator.next();
    if(next instanceof A) // do something
    if(next instanceof B)
        iterator.remove();
}

播种有哪些替代品......

感谢您的建议。

编辑:基类可能有许多子类,而不只是两个,它们的数字可能会及时增长

5 个答案:

答案 0 :(得分:1)

您可以在Base中创建方法,并在AB中覆盖它们。

例如:

class Base{
    public boolean shouldRemove(){
        return false;
    }
    public void doSomething(){
    }
}

class A extends Base{
    @Override
    public void doSomething() {            
    }
}

class B extends Base{
    @Override
    public boolean shouldRemove() {
        return true;
    }
}

然后你不需要知道对象是一个实例的类:

    while(iterator.hasNext()) {
        Base next = iterator.next();
        if(next.shouldRemove()){
            iterator.remove();
        }
        else{
            next.doSomething();
        }
    }

答案 1 :(得分:1)

你真的需要从列表中删除它们吗?你为什么不只是在Base类中做某事(无所事事),然后只是将它覆盖到你想要的类A上。

class Base{
    public void doSomething(){
    }
}


class A extends Base{
    @Override
    public void doSomething(){
        // do something
    }
}

然后你可以遍历列表并在所有对象上调用方法doSomething。

for(Base base : list) {
    base.doSomething();
}

这样只有覆盖doSomething()方法的类才能实际执行某些操作。所有其他类只会在Base类中执行虚拟实现。

如果Base是一个抽象类,您可以将doSomething()声明为抽象类,并让扩展类实现它。使用这种方法,所有类都必须实现您不希望执行任何计算的方法和类,您只需提供该方法的虚拟实现。或者,您甚至可以使用doSomething()方法创建一个接口并且具有(甚至可以做出更好的决策)并让Base类实现它,因为只有扩展类才会实际实现该方法。

答案 2 :(得分:0)

我认为这是一个非常简短明了的解决方案,没有替代方案(没有代码增长), 只需在第二种情况下添加else if而不是if

此外,您可以在函数调用上拆分代码,if语句也不会很大

另一个解决方案是创建将被调用的Map个委托。像这样: interface ISimpleDelegate{ void doSomeLogic(Base b) } `Map delegates = new HashMap();

之后,将您的逻辑添加为实现ISimpleDelegate的匿名类。 delegates.put(A.class, new ISimpleDelegate() { //write your logic here });

我希望这个想法很明确

在您的循环中,您只需致电代表:

while(iterator.hasNext()) {
    Base next = iterator.next();
    delegates.get(next.getClass()).doSomeLogic(next);
}

答案 3 :(得分:0)

instanceof是按类型过滤对象的好方法 - 这就是你想要做的事情。你有一个混合集合,所以你需要某种过滤器,过滤输入(只存储A s)或过滤输出(只处理A s)。

如果您不喜欢“instanceof”,可以使用enum指定类型并添加最终方法以获取Base处的类型:

enum Type { ATYPE, BTYPE };

public Base {

   final private Type type;
   public Base(Type type) { this.type = type; }
   public Type getType() { return type; }
   // ...
}

public A {
   public A() { super(Type.ATYPE); }
}

while(iterator.hasNext()) {
    Base next = iterator.next();
    switch (next.getType) {
      case ATYPE: // do something and break
      case BTYPE: iterator.remove(next); break;
    }
}

答案 4 :(得分:0)

一般来说,避免instanceof的好方法是使用所谓的visitor pattern

对于此模式,您需要一个额外的接口(Visitor),它的实现包含您要执行的代码以及层次结构的所有类中的其他方法,因此在小的情况下这可能是过度的(但是如果不仅AB,还有更多类型,那么它非常方便。

在你的情况下,它看起来像这样:

interface Visitor {
  void visit(A a);
  void visit(B b);
}

class Base {
  abstract accept(Visitor v);
}

class A extends Base {
  accept(Visitor v) {
    v.visit(this);
  }
}

class B extends Base {
  accept(Visitor v) {
    v.visit(this);
  }
}

class MyVisitor implements Visitor {
  visit(A a) {
    doSomethingWithA(a);
  }

  visit(B b) {
    doSomethingWithB(b);
  }
}

它的用法如下:

MyVisitor v = new MyVisitor();
while(iterator.hasNext()) {
    Base next = iterator.next();
    next.accept(v);
}

一个优点是你必须只编写一次大部分代码。如果你想在程序的另一个地方用A和B做其他事情,那就写下另一个Visitor实现。您无需修改​​BaseAB,就像您将doSomething()添加到这些类中一样。

修改 如果子类的数量增加,则需要更改Visitor的所有现有实现。但是,至少编译器会告诉你这一点。使用instanceof,您可能最终忘记了需要添加处理子句的位置。这最多可以在运行时检测到,而访问者模式可以为您提供编译时的安全性。