Ява: отражение чрезмерное? - PullRequest
1 голос
/ 12 января 2011

Мне интересно, не злоупотребляю ли я Java-отражением.
У меня есть класс, который является держателем данных для пары карт. У меня есть публичные методы get (...), которые дают ключ в качестве входных данных, возвращают значение, связанное с ним в соответствующей карте.
Поскольку карты велики, я загружаю их только тогда, когда действительно хочу получить к ним доступ. Итак, в каждом методе get (...) я проверяю, является ли карта нулевой. Если это так, я вызываю соответствующий метод loadMap (..).
Вот пример кода

 public getId(String name)  
 {
     try
     {
     if(nameMap1 == null)
        loadNameMap1();
     } catch(...) {....}

     return nameMap1.getId(name);
 }

Проблема в том, что у меня есть несколько карт. Итак, для загрузки каждой карты у меня есть другой метод loadMap (..) и блок try catch в методах get (...). Поэтому вместо этого я написал метод loadMap (Object map, String methodName), который использует отражение для вызова соответствующего метода и обрабатывает все исключения.

private synchronized void loadMap(Object map, String methodName)
{
if (map == null)
    try
    {
    Method method = this.getClass().getDeclaredMethod(methodName, new Class[0]);
    method.invoke(this, new Object[0]);
    } 
    catch (..)
}

Я злоупотребляю здесь отражением? Есть лучший способ сделать это? Означает ли это «ограниченное использование отражения», как написано в «1010 * Effective Java» Джошуа Блоха
(Примечание: я не могу реорганизовать класс в несколько классов)

Ответы [ 3 ]

3 голосов
/ 12 января 2011
// could also be static
private Map<String, Callable<Map>> myLoaders;

private synchronized void loadMap(Object map, String mapName)
{
if (map == null)
    try
    {
       Callable<Map> mapLoader = myLoaders.get(mapName);
       map = mapLoader.call();
    } 
    catch (..)
}

// and in the constructor or other init code
myLoaders.put("map1", new Callable<Map>(){
     Map call(){
        // load map 1
     }});

Я думаю, что если все, что вы делаете, это переносите общую логику try / catch из нескольких методов, где ее необходимо повторить в одном месте, это неправильный подход.Таким образом, вы теряете много поддержки проверки ошибок компилятора.Некоторые люди для этого используют такой инструмент, как Aspect / J, но я думаю, что вам просто нужно смириться с тем фактом, что у Java нет реальных возможностей для этого, уменьшить беспорядок до минимума с помощью общих частных функций и принять парускопировать / вставить строки.Пока в этих строках нет «реального кода», это не очень вредное дублирование кода.

Итак:

 public getId(String name){
     try{
        if (nameMap1 == null)
            loadNameMap1();
        }
      catch (....){
          privateHelperFunctionThatCutsThisDownToOneLine(name, "id", "nameMap1");
      }
  }

  // you are left with the above repetitive three (or seven) lines,
  // but that is Java for you...
  // in return, you get nice, static compile-time error checking


 private void privateHelperFunctionThatCutsThisDownToOneLine(){
      // all the long repeated code in the exception handler
      // goes here.
 }
2 голосов
/ 12 января 2011

Вы не хотите загружать все карты, потому что они слишком большие. Но, используя ваш метод, вы в конечном итоге получите все, что загружено в память. Вы можете взглянуть на ehcache , который может быть настроен как система ленивых карт с удалением элементов, когда в них больше нет необходимости.

2 голосов
/ 12 января 2011

Я бы сказал, что да, вы злоупотребляете рефлексией.

Возможно, вам следует использовать более внушительный подход

public interface MapMaker <K,V> {
public Map<K,V> create();
}

public class LazyMap<K,V> implements Map<K,V> {

private MapMaker<K,V> creation;
private Map<K,V> theMap = null;

public LazyMap( MapMaker<K,V> creation) {
  this.creation=creation;
}

protected Map<K,V> getMap() {
  if( theMap == null) {
    synchronized(this) {
      if( theMap == null ) {
         theMap = creation.create();
      }
    }
  }
  return theMap;
}
//Map interface
public V get(Object key) { return getMap().get(key); }
//repeat for all
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...