簡體   English   中英

一種實現加載大量資源的共享類的絕佳方法(使用Java)

[英]An elegant way to implement shared classes that load heavy resources (in Java)

我有幾個類可以用作一些繁重的庫的包裝器,例如解析器,標記器和其他資源。 所有這些庫都有一個共同點:它們都有一個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”之類的幾種方法,以便於單點加載資源。 該類還將檢查每個資源是否已經實例化,等等。 這些有什么嗎?

問候。

我將創建一個類似於Factory的類來創建解析器和Tager等,並讓此類為某些文件名緩存結果,以便對getParser(filename)的第一個調用將導致創建解析器,而所有下一個都將返回緩存的解析器。 這類似於Singleton,但是如果您具有工廠的通用接口,則可以創建一個返回模擬的工廠,而不是創建整個解析器。

這樣,您只需確保在程序中的某個地方為所有解析器和標記器創建了一個工廠,並擁有從程序中獲取此對象的好方法。

解析器似乎是不可變的。 (如果解析器不為null,則init不執行任何操作)為什么還要麻煩使其變為靜態? 使初始化構造函數和解析器成為ParswerWrapper的成員。 創建另一個類(或將System.setProperty()用作丑陋的hack),該類是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表示單個實例。

為什么不將ResourceManager設為靜態,然后在初始化包裝器之前調用所有create方法? 這避免了單例模式,並且可能更緊密地匹配您想要實現的目標。

文件會更改嗎?

如果不是:在靜態初始化器中將其作為資源加載。

如果是這樣的話:“從上方進行參數設置”將對象一直傳遞到構造函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM