为扩展类提供特定的行为?

时间:2012-10-20 03:12:31

标签: java

如何对类Fruit进行多次扩展,并根据对象所属的类/类型,在此水果上执行相同的方法,但具有不同的功能?

示例:我正在使用FruitManager向fruitstore添加新的Fruit fruit = new Apple();。如果这个水果是苹果,我当然希望将其添加到苹果列表中。 Elso到香蕉列表。 现在,如果我有10种水果,我不想创建10个函数,如addBanana()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);
    }
}

3 个答案:

答案 0 :(得分:5)

让我的kludge成为答案。考虑使用HashMap<Class<? extends Fruit>, List<Fruit>>的HashMap。像这样:

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

答案 1 :(得分: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)添加到与班级中的列表不同的列表。

答案 2 :(得分:1)

List<Fruit> apples = new ArrayList<Apple>();

首先,这在Java中无效,因为水果列表无法指向苹果列表,因为List<Fruit>可能包含任何水果,即苹果或香蕉,而ArrayList<Apple>只能包含苹果。

其次,当你有这样的继承链时,通常不会将它们存储在单独的列表中。您可以将它们存储在单个列表List<Fruit>中,并且对此列表中的每个元素执行的任何操作都将具有多态行为,并且基于Fruit的实际类型,行为可能会有所不同,在相应的类中定义。

因此,您应该重新考虑您认为需要单独存储它们的用例。