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

では、代替手段は何ですか...

アドバイスありがとうございます。

編集:基本クラスには2つだけでなく多くのサブクラスがあり、その数は時間とともに増加する可能性があります

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は、いわゆるビジター パターンを使用することです。

このパターンでは、追加のインターフェース (ビジター)、実行したいコードを含むその実装、および階層のすべてのクラスに追加のメソッドが必要です。と だけ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);
}

利点は、ほとんどのコードを 1 回だけ記述する必要があることです。プログラムの別の場所で A と B を使って別のことをしたい場合は、Visitor の別の実装を書くだけです。これらのクラスに追加する場合と同様Baseに、を変更する必要はありません。ABdoSomething()

編集: サブクラスの数が増えた場合は、既存のすべての実装を変更する必要がありますVisitor。ただし、少なくともコンパイラはそれについて教えてくれます。instanceof処理句を追加する必要がある場所を忘れてしまう可能性があります。これはせいぜい実行時に検出できますが、訪問者パターンはコンパイル時の安全性を提供します。

于 2011-02-21T11:49:42.013 に答える
0

私は非常に短く明確な解決策であり、(コードが成長することなく)代替手段はないと思います.2番目のケース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」だけが気に入らない場合は、 を使用し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;
    }
}
于 2011-02-21T10:36:47.410 に答える