5

您好,我想知道有什么更优雅的替代方案来代替这样的东西:

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();
}

看看有什么替代方案...

谢谢你的建议。

编辑:基类可能有许多子类,而不仅仅是两个,它们的数量可能会随着时间增长

4

5 回答 5

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该类实现它,因为只有扩展类才能实际实现该方法。

于 2011-02-21T10:47:17.923 回答
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();
        }
    }
于 2011-02-21T10:37:03.757 回答
0

一般来说,避免instanceof使用的一个很好的解决方案是使用所谓的访问者模式

对于这种模式,您需要一个额外的接口(访问者)、一个包含您想要执行的代码的实现以及层次结构的所有类中的一个额外的方法,所以在小情况下这可能是多余的(但它非常如果不仅有Aand B,而且还有更多类型,则很方便)。

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

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 做其他事情,只需编写另一个访问者的实现。您不需要修改Base,就像添加这些类A一样。BdoSomething()

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

于 2011-02-21T11:49:42.013 回答
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);
}
于 2011-02-21T10:36:19.420 回答
0

instanceof是按类型过滤对象的好方法 - 这就是您想要做的。您有一个混合集合,因此您需要某种过滤器,或者过滤输入(只存储As)或过滤输出(只处理As)。

如果你只是不喜欢“instanceof”,你可以使用 anenum来指定类型并添加一个 final 方法来获取类型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;
    }
}
于 2011-02-21T10:36:47.410 回答