Ago*_*noX 9 java factory-method static-initializer
我有一个由执行文件处理的类实现的接口,比如搜索或其他什么.
public interface FileProcessorInterface {
public void processFile(String fileName);
}
Run Code Online (Sandbox Code Playgroud)
然后我对每种文件类型都有不同的实现:
public class TxtProcessor implements FileProcessorInterface {
@Override public void processFile(String fileName) { //do the work }
}
Run Code Online (Sandbox Code Playgroud)
因此我有处理器的Utilizer,它有一个允许注册每个类的方法,如下所示:
class Utilizer {
Map <String, Class> registered = new HashMap<>();
public void registerClass(String fileExt, Class clazz) {
registered.put(fileExt, clazz);
}
public void processFile(String fileName) {
//1) get the registered class from registered map (omitted because easy and not relevant)
//2) create an instance of the class using reflection (omitted because easy and not relevant)
FileProcessorInterface p = ....
p.processFile(fileName);
}
Run Code Online (Sandbox Code Playgroud)
到目前为止还可以.
现在,我提供了许多我的界面实现.
我很想为每个实现类提供一个静态初始化程序,它在Utilizer中注册自己,在我之前的TxtProcessor的情况下,它将是:
class TxtProcessor implements FileProcessorInterface {
//previous code
static {
Utilizer.registerClass("txt", TxtProcessor.class);
}
}
Run Code Online (Sandbox Code Playgroud)
问题是永远不会调用这个静态方法,因为在应用程序的"静态可达"代码中没有对我的TxtProcessor类的引用,因为它是通过反射实例化的.所以jvm不会调用静态初始化器.
假设我有两个部分:"通用代码",即Utilizer,另一方面是实现; 它必须被认为是在dinamically提供的东西,因此Utilizer部分不知道它.
事实上,这个想法恰恰相反,每个类都会注册自己而不使用Utilizer.
我很难设想一个解决方案,它不会在Utilizer端提供某种形式的"知识"实现(并且保持简单),只是因为没有调用静态初始化器的问题.怎么克服这个?
在这里使用反射似乎是最合适的。这就像是为了做到这一点。
所有你需要的是一个小静块Utilizer为
static {
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("path.to.all.processors.pkg"))
.setScanners(new SubTypesScanner())
);
reflections.getSubTypesOf(path.to.all.processors.pkg.FileProcessor.class);
}
Run Code Online (Sandbox Code Playgroud)
如果您不想要第三方依赖项,只需将FileProcessors.properties文件添加到您的类路径
txt=path.to.all.processors.pkg.TxtProcessor
doc=path.to.all.processors.pkg.DocProcessor
pdf=path.to.all.processors.pkg.PdfProcessor
Run Code Online (Sandbox Code Playgroud)
然后将所有列出的类注册Utilizer为
static {
Properties processors = new Properties();
try {
processors.load(Utilizer.class
.getResourceAsStream("FileProcessors.properties"));
} catch (IOException e) {
e.printStackTrace();
}
for (String ext : processors.stringPropertyNames()) {
Utilizer.registerClass(ext, Class.forName(processors.getProperty(ext));
}
}
Run Code Online (Sandbox Code Playgroud)
这不再需要每次都使用静态块FileProcessor。