1

クラスのいくつかの拡張機能を持ちFruit、オブジェクトのクラス/タイプに基づいて、このフルーツで同じメソッドを異なる機能で実行するにはどうすればよいですか?

例: a を使用し て、果物屋FruitManagerに新しい を追加Fruit fruit = new Apple();しています。この果物がりんごなら、もちろんりんごリストに追加したいです。またバナナリストへ。addBanana()10 種類の果物があれば、などの 10 個の関数を作成したくありませんaddApple()。そして、私も、適切な果物のリストを取得するために複雑な if-else ステートメントを使用したくありません。

追加しているオブジェクトのタイプに基づいてフルーツリストを同じ方法で取得できますか?

class Fruit;
class Apple extends Fruit;
class Banana extends Fruit;

class FruitStore {
    List<Fruit> apples = new ArrayList<Apple>();
    List<Fruit> bananas = nwe ArrayList<Banana>();
}

class FruitManager {
    FruitStore store;

    //called from somewhere with Fruit fruit = new Apple();
    addFruit(Fruit fruit) {
        //how could things like this be done in one statement?
        store.<get list apples or bananas>.add(fruit);
    }
}
4

3 に答える 3

5

私のクラッジを答えにします。の HashMap の使用を検討してくださいHashMap<Class<? extends Fruit>, List<Fruit>>。このようなもの:

class FruitStore {
   private Map<Class<? extends Fruit>, List<Fruit>> fruitMap = 
         new HashMap<Class<? extends Fruit>, List<Fruit>>();

   public void addFruit(Fruit fruit) {
      Class<? extends Fruit> fruitClass = fruit.getClass();
      List<Fruit> fruitList = fruitMap.get(fruitClass);
      if (fruitList == null) {
         fruitList = new ArrayList<Fruit>();
         fruitMap.put(fruitClass, fruitList);
      }
      fruitList.add(fruit);
   }

   public void displayStore() {
      for (List<Fruit> fruitList : fruitMap.values()) {
         System.out.println(fruitList);
      }
   }
}

私はこれをテストしました:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FruitManager {
   public static void main(String[] args) {
      FruitStore fruitStore = new FruitStore();
      for (int i = 0; i < 20; i++) {
         if (i % 3 == 0) {
            fruitStore.addFruit(new Banana());
         } else {
            fruitStore.addFruit(new Apple());
         }
      }

      fruitStore.displayStore();
   }
}

abstract class Fruit {
   public abstract String getName();

   @Override
   public String toString() {
      return getName();
   }
}

class Apple extends Fruit {

   private static final String NAME = "Apple";

   @Override
   public String getName() {
      return NAME;
   }

}


class Banana extends Fruit {

   private static final String NAME = "Banana";

   @Override
   public String getName() {
      return NAME;
   }

}

class FruitStore {
   private Map<Class<? extends Fruit>, List<Fruit>> fruitMap = 
         new HashMap<Class<? extends Fruit>, List<Fruit>>();

   public void addFruit(Fruit fruit) {
      Class<? extends Fruit> fruitClass = fruit.getClass();
      List<Fruit> fruitList = fruitMap.get(fruitClass);
      if (fruitList == null) {
         fruitList = new ArrayList<Fruit>();
      }
      fruitList.add(fruit);
      fruitMap.put(fruitClass, fruitList);
   }

   public void displayStore() {
      for (List<Fruit> fruitList : fruitMap.values()) {
         System.out.println(fruitList);
      }
   }
}
于 2012-10-20T03:40:46.273 に答える
1
List<Fruit> apples = new ArrayList<Apple>();

まず、これは Java では有効ではありません。フルーツのリストはリンゴのリストを指すことができないためです。List<Fruit>リンゴやバナナなどのフルーツを含む可能性があるため、リンゴArrayList<Apple>のみを含むことができます。

第二に、このような継承チェーンがある場合、通常、それらを別々のリストに保存しません。それらを単一のリストに格納し、List<Fruit>このリスト内の各要素に対して実行されるすべての操作は、多態的な動作を持ち、実際の型に基づいてFruit、対応するクラスで定義されているように動作が異なる可能性があります。

そのため、それらを別々に保管する必要があると感じたユースケースを再考する必要があります。

于 2012-10-20T03:21:03.600 に答える
1

addBanana(..)、などの必要性を回避することはできますが、addApple(..)リフレクションを使用してプログラムの効率を大幅に下げたくない場合を除き、これはいくつかの if-else ステートメントなしでは実行できません。

public void addFruit(Fruit fruit) {
    if (fruit instanceof Apple) {
        store.apples.add(fruit);
    } else if (fruit instance of Banana) {
        store.bananas.add(fruit);
    } else if ... { }
}

どうしてもリフレクション方式を使いたい場合は・・・こちらですが、お勧めしません。

public void addFruit(Fruit fruit) {
    try {
        Class<Fruit> clazz = fruit.getClass();
        String clazzName = clazz.getName();
        String listName = clazzName.toLowercase() + "s";
        Class<FruitStore> fsClazz = store.getClass();
        Field listField = fsClazz.getDeclaredField(listName);
        listField.setAccessible(true);
        List<Fruit> list = (List<Fruit>) listField.get(store);
        list.add(fruit);
    } catch (Exception e) {
        // failed to add fruit
        e.printStackTrace();
    }
}

注: リフレクション メソッドはテストされていませんが、発生する可能性がある唯一の問題はField#get、その値への参照ではなく、その値のコピーへの参照を返し、その結果list.add(fruit)、クラス内のリストとは異なるリストに追加されることです。

于 2012-10-20T03:16:33.217 に答える