实现承载大量资源的共享类的优雅方式(Java)
我有几个类,它们在一些繁重的lib上充当包装器,比如解析器、标记器和其他资源。所有这些lib都有一个共同点:它们有一个load/init方法,该方法将序列化模型(一个大文件)作为输入,并返回一个类,该类可用于执行具体操作,例如解析文本 为了说明这种情况,假设我有一个具体的解析器库来进行解析,为此我创建了以下类来包装它:实现承载大量资源的共享类的优雅方式(Java),java,design-patterns,oop,resources,Java,Design Patterns,Oop,Resources,我有几个类,它们在一些繁重的lib上充当包装器,比如解析器、标记器和其他资源。所有这些lib都有一个共同点:它们有一个load/init方法,该方法将序列化模型(一个大文件)作为输入,并返回一个类,该类可用于执行具体操作,例如解析文本 为了说明这种情况,假设我有一个具体的解析器库来进行解析,为此我创建了以下类来包装它: public class ParserWrapper { private static final ConcreteParser parser = null;
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”,以便有一个单点来加载资源。这个类还将检查每个资源是否已经实例化,等等。对这些有什么想法吗
关于。为什么不将ResourceManager设置为静态,然后在初始化包装器之前调用所有的create方法?这避免了单例模式,并且可能更符合您想要实现的目标。为什么不将ResourceManager设置为静态,然后在初始化包装器之前调用所有创建方法?这避免了单例模式,可能更符合您想要实现的目标。我将创建一个类似工厂的类来创建解析器和标记器等,并将该类缓存某些文件名的结果,以便第一次调用getParser(filename)将导致创建一个解析器,接下来的所有操作都将返回缓存的解析器。 这与Singleton类似,但是如果您有一个factorys的公共接口,那么就允许创建一个返回mock的工厂,而不是创建整个解析器
这样,您只需确保在程序中的某个地方为所有解析器和标记器创建一个工厂,并有一种从程序中获取此对象的好方法。我将创建一个类似工厂的类来创建解析器和标记器等,并将该类缓存某些文件名的结果,以便第一次调用getParser(filename)将导致创建一个解析器,接下来的所有操作都将返回缓存的解析器。 这与Singleton类似,但是如果您有一个factorys的公共接口,那么就允许创建一个返回mock的工厂,而不是创建整个解析器
这样,您只需确保在程序中的某个地方为所有解析器和标记器创建一个工厂,并有一个从程序中获取这些对象的好方法。文件是否会更改 如果不是:将其作为静态初始化器中的资源加载
如果是这样:“从上面参数化”通过构造函数传入对象,一直向下传递。文件是否会更改 如果不是:将其作为静态初始化器中的资源加载
如果是这样的话:“从上面参数化”通过构造函数传入对象,一直向下传递。似乎解析器是不可变的。(若解析器不为null,init什么也不做)那个么为什么还要麻烦使它成为静态的呢?使init成为ParswerWrapper的构造函数和解析器成员。创建另一个类(或者使用System.setProperty()作为难看的攻击),该类是一个单例,其唯一任务是保留引用。如果您提前知道需要哪些文件,您甚至可以使用枚举 #一,
使用枚举可以保证每个枚举值只有一个实例。时期支持JVM以确保它们不能被克隆、反序列化、在类加载器之间拆分等。枚举表示单个实例。解析器似乎是不可变的。(若解析器不为null,init什么也不做)那个么为什么还要麻烦使它成为静态的呢?使init成为ParswerWrapper的构造函数和解析器成员。创建另一个类(或者使用System.setProperty()作为难看的攻击),该类是一个单例,其唯一任务是保留引用。如果您提前知道需要哪些文件,您甚至可以使用枚举 #一,
使用枚举可以保证每个枚举值只有一个实例。时期支持JVM以确保它们不能被克隆、反序列化、在类加载器之间拆分等。Enum表示单个实例。+1到工厂,因为以后可以轻松更改细节,而不会破坏任何+1到工厂,由于细节可以很容易地在以后更改,而不会破坏任何东西,因此最好绝对确保ConcreteParser单例是线程安全的!最好绝对确定ConcreteParser单例是线程安全的!
/*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);
}
}
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) {...}
}