Элегантный способ реализовать разделяемые классы, которые загружают большие ресурсы (в Java) - PullRequest
0 голосов
/ 19 июля 2009

У меня есть несколько классов, которые работают как обертки над некоторыми тяжелыми библиотеками, такими как парсеры, тэггеры и другие ресурсы. У всех этих библиотек есть одна общая черта: у них есть метод load / init, который принимает в качестве входных данных сериализованную модель (большой файл) и возвращает класс, который можно использовать для выполнения конкретных задач, таких как синтаксический анализ текста.

Чтобы проиллюстрировать эту ситуацию, скажем, у меня есть библиотека ConcreteParser для анализа, для которой я создал следующий класс:

public class ParserWrapper {
    private static final ConcreteParser parser = null;

    private static void init(String modelFileName) {
        if (parser == null)
            parser = ConcreteParser.load(modelFileName);
    }

    public static Result parse(input) {
        if (parser == null) throw new RuntimeException(...);
        return parser.parse(input);
    }

}

Как видите, для этого требуется, чтобы клиент сначала вызвал init перед анализом, что, безусловно, является нет-нет. Я также попробовал решение, основанное на шаблоне Singleton, но я все еще думаю, что есть лучший способ сделать то, что я хочу.

ConcreteParser является статическим, поскольку каждая модель загружается относительно долго и потребляет много памяти. Поэтому мне нужно, чтобы они были доступны всем классам, которые его используют.

Итак, мой вопрос: есть ли другой (более элегантный) способ сделать то, что я хочу? Как я могу улучшить этот код? Я думал о создании класса ResourceManager, который имел несколько методов, таких как «createParser» и «createTagger», чтобы иметь единую точку для загрузки ресурсов. Этот класс также проверяет, был ли создан каждый ресурс, и так далее. Есть мысли по этому поводу?

Привет.

Ответы [ 4 ]

3 голосов
/ 19 июля 2009

Я бы создал класс, подобный Фабрике, для создания Parser, Tager и т. Д., И имел бы этот кэш-результаты для определенных имен файлов, так что первый вызов getParser (filename) вызовет создание анализатора, а все последующие вернут кэшированный парсер. Это похоже на Singleton, но если у вас есть общий интерфейс для factorys, позволяет создать фабрику, которая возвращает макеты вместо создания всего синтаксического анализатора.

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

1 голос
/ 19 июля 2009

Кажется, что парсер неизменен. (если синтаксический анализатор не является нулевым, init ничего не делает), так зачем беспокоиться о том, чтобы сделать его статическим? Сделайте init конструктором и парсером члена ParswerWrapper. Создайте другой класс (или используйте System.setProperty () в качестве некрасивого хака), который является Singleton, единственная задача которого - удерживать ссылки Если вы заранее знаете, какие файлы вам нужны, вы даже можете использовать Enum!

# 1

/*package*/ class ParserWrapper implements ParserWrapperInterface{ 
  private ConcreteParser p;
  public ParserWrapper(String filename) {
    p = ConcreteParser.load(p);
  }

  public Result parse(InputStream in) {...}
}

public Enum ParserManager {
  instance;

  private Map<String, ParserWrapper> map = new HashMap<...>()

  public get(String filename) {
    if(!map.containesKey(filename)) {
      synchronized(ParserManager.class) {
        if(!map.containesKey(filename)) {
          map.put(filename, new ParserWrapper(filename));
        }
      }
    }
    return map.get(filename);
  }
}

# 2

public Enum Parsers {
ModelFoo("foo.mdl"), ModelBar("bar.mdl");

private ConcreteParser p;

public Parser(String fname) {
p = ConcreteParser.load(fname);
}

public Result parse(InputStream in) {...}
}

Использование Enum гарантирует, что когда-либо будет только один экземпляр каждого значения Enum. Период. Предполагается, что JVM не может быть клонирована, десериализована, разделена между загрузчиками классов и т. Д. Enum означает один экземпляр.

0 голосов
/ 19 июля 2009

Изменяется ли файл когда-либо?

Если нет: загрузите его как ресурс в статический инициализатор.

Если это так: «Параметр сверху» Передайте объекты через конструкторы до конца.

0 голосов
/ 19 июля 2009

Почему бы вам не сделать ResourceManager статичным, а затем вызвать все ваши методы create перед инициализацией ваших оболочек? Это позволяет избежать одноэлементного паттерна и, возможно, более точно соответствует тому, чего вы хотите достичь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...