2013-12-06 3 views
1

Я перерабатываю класс под названием ConfigNode, который хранит 50 «свойств». Каждое свойство является собственным объектом. Все свойства являются необязательными, и большую часть времени многие из них не установлены.Менее подробный способ сделать ленивую загрузку

В настоящее время класс написан таким образом, что при его создании создается все 50 свойств. Когда вы создаете миллион объектов Config, Java говорит мне, что я использую 2,5 гигабайта памяти. Когда я комментирую экземпляр свойств, Java говорит, что я использую 300 МБ.

Эталон код я использую

Runtime.getRuntime().gc(); 
// do my stuff 
Runtime.getRuntime().gc(); 
long memory = Runtime.getRuntime().totalMemory(); 
System.out.println("Memory used: " + memory/1000000 + " MB"); 

Так что я имею в виду переписывать класс для ленивой нагрузки свойство, когда он доступен, но, чтобы писать что-то вроде

// This is probably not thread safe, so it could be even more verbose 
public NodeProperty propOne() { 
    if (propOne == null) { 
     propOne = new NodeProperty(...) 
    } 
    return propOne 
} 

И тогда сделать это для всех свойств, кажется, довольно многословным. Есть ли что-нибудь в Java, которое может помочь мне уменьшить количество кода, который я должен написать (и, следовательно, поддерживать)?

Вот как NodeConfig выглядит

public class NodeConfig { 

    public NodeProperty pVersion = new NodeProperty("Spec Version", Status.REQUIRED, Visibility.HIDDEN); 
    public NodeProperty pTwoWay = new NodeProperty("Two way", Status.OPTIONAL, Visibility.VISIBLE); 
    public NodeProperty pBinary = new NodeProperty("Binary mode", Status.OPTIONAL, Visibility.HIDDEN); 

    // more properties 

    public NodeConfig() { 
     // 
    } 
} 
+0

«все 50 свойства также созданный экземпляр ». Могли бы вы изменить этот конструктор так, чтобы вместо создания объектов, которые вы просто сохраняете null, если свойство не существует или не должно использоваться? –

+0

'totalMemory()' возможно, не делает то, что вы думаете, это «общий объем памяти, доступный в настоящее время для текущих ** и будущих ** объектов, измеренных в байтах». (http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#totalMemory()) – berry120

+2

Только идея у меня есть, может быть, что-то с отражением. Попробуйте написать один метод для всех 50 вызовов. Кроме этого, попробуйте рефакторинг вашего объекта. Если есть много свойств, которые он не использует, это признак того, что у него слишком много состояний, слишком большая ответственность. –

ответ

0

подход 1
Вот еще один подход можно использовать, учитывая NodeConfig код: общественный класс NodeConfig {

public NodeProperty pTwoWay; 
    public NodeProperty pBinary; 

    // more properties 

    public NodeConfig() { 
     // 
    } 

    public NodeProperty getProperty(NodePropertyEnum nodeProp) { 
     switch(nodeProp) { 
      case TWO_WAY: 
       if (pTwoWay != null) {return pTwoWay;} 
       pTwoWay = new NodeProperty("Two way", Status.OPTIONAL, Visibility.VISIBLE); 
      case BINARY_MODE: 
       if (pBinary != null) {return pBinary;} 
       pBinary = new NodeProperty("Binary mode", Status.OPTIONAL, Visibility.VISIBLE); 
      // other cases 
      default: 
       throw new IllegalArgumentException(); 
     } 
    } 
} 

Approach 2
Похож на корпус для дизайна Singleton. Вместо того, чтобы проверять для propOne экземпляр null, будет лучше, если вы сделаете все классы свойств singleton. Что-то вроде:

public class NodeProperty { 

    private static volatile NodeProperty instance = null; 

    private NodeProperty() { 
     // instantiatin logic 
    } 

    public NodeProperty getInstance() { 
     if(instance == null) { 
      synchronized(NodeProperty.class) { 
       if(instance==null) { 
        instance = new NodeProperty(); 
       } 
      } 
     } 
    } 

} 
+2

'instance' должен быть' volatile' для двойной проверки блокировки, чтобы быть правильным. – MikeFHay

+0

Чтобы улучшить подход-1, вы можете использовать реализацию LRU cache (LinkedHasMap) с колпачком, равным 10, таким образом, система автоматически отключит свойства, которые не используются, что приведет к уменьшению отпечатка пальца вашего класса , –

2

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

import com.google.common.base.Supplier; 
import com.google.common.base.Suppliers; 

private Supplier<NodeProperty> propOneSupplier = 
    Suppliers.memoize(() -> new NodeProperty(...)); 

public NodeProperty propOne() 
{ 
    return propOneSupplier.get(); 
} 

(Обратите внимание, что это поставщик гуавы, не java.util.function.Supplier)

Если вы не используете Java 8 все же это будет немного более многословен:

private Supplier<NodeProperty> propOneSupplier = 
     Suppliers.memoize(
    new Supplier<NodeProperty>() 
    { 
     @Override 
     public NodeProperty get() 
     { 
      return new NodeProperty(...); 
     } 
    }); 
Смежные вопросы