2013-02-24 4 views
1

Мне нужно инициализировать несколько объектов od разных типов из определений XML в beans. У меня есть структура каталогов:Карта карт разных типов

data \ 
|_ plant \ 
| |_ pine.xml 
| |_ cucumber.xml 
|_ animal \ 
| |_dog.xml 
| |_cat.xml 
|_ fungus \ 
... 

Я хочу сохранить его упорядоченным в двухуровневой карте: карта первого уровня хранит карты второго уровня. Каждая карта второго уровня содержит объекты одного типа (класса растений/животных/грибов ...). Каждый класс расширяет класс Dict, который имеет некоторые общие поля и методы (имя/getName()/setName(), desc/getDesc()/setDesc(), toString(), equals() и т. Д.

, чтобы облегчить создание всех этих объектов, я хочу иметь фабричный метод Dict.fabricateAll(). И вот в чем проблема: как создать карты второго уровня, чтобы они имели точные параметры типа. Я не хочу, чтобы HashMap < String, Dict > но HashMap < String, завод >, HashMap < String, животных и т.д. >

Сейчас я следующий код:

public static Map<String, Map<String, ? extends Dict>> fabricateAll() { 
    File topDir = new File(Dict.defDir); 
    File[] subDirs = topDir.listFiles(); 
    Map<String, Map<String, ? extends Dict>> dicts = new HashMap<>(subDirs.length); 

    String type; 
    String handle; 
    Map<String, ? extends Dict> dict; 

    for (File subDir : subDirs) { 
     type = subDir.getName(); 
     File[] xmlFiles = subDir.listFiles(new FilenameFilter() {public boolean accept(File dir, String name) { return name.toLowerCase().endsWith(".xml"); }}); 
     dict = new HashMap<>(xmlFiles.length); 

     for (File defFile : xmlFiles) { 
      handle = defFile.getName(); 
      handle = handle.substring(0, handle.lastIndexOf('.')-1); 

      try { 
       Class c = Class.forName(type); 
       Constructor bob = c.getConstructor(Class.forName("java.lang.String")); 
       dict.put(handle, bob.newInstance(handle)); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
     dicts.put(type, dict); 
    } 
    return dicts; 
} 

Но есть проблема с строкой: dict.put (handle, bob.newInstance (handle));

Сообщение об ошибке: «Метод положить в интерфейсной карте < K, V > не может быть применен к данным типам Обязательно:. Строка, CAP # 1 Найдено: String, Object

Да, newInstance() создает объекты и вероятно, должен быть какой-то актерский состав, но для чего? Я не хочу просто «(Dict)» здесь, я бы предпочел «(Plant)», «(Animal)» ... по мере необходимости. Как это сделать?

+0

Вы возвращаете 'Map > '. Таким образом, клиентский код не может знать, содержат ли карты растения, кошки или что-то еще. Все, что он знает, это то, что они являются экземплярами Дикта. Поэтому бросьте его на Дикта, и все будет хорошо. Тем не менее, я бы не использовал рефлексию для этого, а фабрики (один завод на тип Dict), что позволило бы делать то, что вы хотите. –

+0

Но животное может бежать(), пока растение не может. Если я передам его в Dict, у меня нет возможности запускать run(), кроме ручного литья в Animal. Что касается подхода «один завод за диктатор»: вы имеете в виду, что у меня должен быть «публичный статический состав (строковый дескриптор)» в каждом из подтипов Dict и вместо вызова «bob.newInstance (handle)»: dict. put (handle, c.getMethod ("fabricate", Class.forName ("java.lang.String")))? Это дает ту же ошибку. – Forseti

+0

Когда у вас есть 'Map ', у вас нет способа узнать, что карта содержит в любом случае. Все, что вы можете сделать, это проверить, является ли это значение экземпляром Plant или Animal (с использованием 'instanceof'), и передать значение для Plant или Animal. Итак, что вы получаете от создания карты «Карта », так как вы возвращаете ее как «Map '.Ваша фабричная идея действительно является решением. Вам понадобится метод возврата Plant или Animal (в зависимости от класса), и вам понадобится карта типа «Map ' или типа «Map », в зависимости от в каталоге. –

ответ

1

Отправляйте объект в Dict. Это преимущество плимоморфизма - вам не нужно ссылаться на определенные подклассы. Вы можете написать код со ссылками только на один базовый класс Dict. Это дает вам:

  • а) Сыпучая муфта - нет времени компиляции зависимостей от конкретных подклассов
  • б) Exetensibility - вы можете добавлять подклассы без необходимости изменять этот код.

Да, есть способы добиться того, о чем вы просили (на ум приходит большое предложение оператора), но ничего, что я бы рекомендовал.