假设您有存储在磁盘上的文件,您需要加载它们。文件有3种类型,其中包含*.ext1
,*.ext2
和*.ext3
。所以我有三个load
方法,每个方法应该通过不同的锁同步。我应该用DI框架将这种行为注入我的服务中。 以下哪种方式更好?
似乎第一种方式是显而易见的。但是什么让我不确定 - 单一责任的原则以及你永远不会想要加载所有三个扩展的事实:你只会加载1& 3或仅2& 3.
1)所有文件类型加载器的通用接口:
public interface FileLoader {
void loadFilesOfExt1();
void loadFilesOfExt2();
void loadFilesOfExt3();
}
//The most obvoius solution, but doesn't it break the principle of single responsibility?
//It also has one more dwawback - I want to synchronize each method by different lock, and it requires using of locks
public class FileLoaderImpl implements FileLoader {
public void loadFilesOfExt1() { /* impl */ }
public void loadFilesOfExt2() { /* impl */ }
public void loadFilesOfExt3() { /* impl */
}
2)每种文件的特定界面:
//It looks pretty weird to have three interfaces with the same API
public interface Ext1Loader { void load(); }
public interface Ext2Loader { void load(); }
public interface Ext3Loader { void load(); }
public class Ext1LoaderImpl extends Ext1Loader { public synchronized void load() { /* impl */ } }
public class Ext2LoaderImpl extends Ext2Loader { public synchronized void load() { /* impl */ } }
public class Ext3LoaderImpl extends Ext3Loader { public synchronized void load() { /* impl */ } }
3)界面层次结构:
//Isn't it an overengeneering? 3 Empty interfaces
public interface FileLoader { void load(); }
public interface Ext1Loader extends FileLoader {}
public interface Ext2Loader extends FileLoader {}
public interface Ext3Loader extends FileLoader {}
public class Ext1LoaderImpl extends Ext1Loader { public synchronized void load() { /* impl */ } }
public class Ext2LoaderImpl extends Ext2Loader { public synchronized void load() { /* impl */ } }
public class Ext3LoaderImpl extends Ext3Loader { public synchronized void load() { /* impl */ } }
4)单一界面:
//This makes me feel like all implementations `Ext1Loader`, `Ext2Loader` and `Ext3Loader` are interchangable.
//But actually you may want to inject `Ext1Loader` nad `Ext3Loader` simultaneously into your class
public interface FileLoader { public void load(); }
public class Ext1Loader implements FileLoader { public synchronized void load() { /* impl */ } }
public class Ext2Loader implements FileLoader { public synchronized void load() { /* impl */ } }
public class Ext3Loader implements FileLoader { public synchronized void load() { /* impl */ } }
答案 0 :(得分:2)
第三种解决方案在这里看起来像是最安全的解决方案。但是添加标记接口似乎不会过度工程。
我建议你考虑我对你的任务的看法:
do
{
...
}
while(!Display.isCloseRequested())
只有一个接口,实现将加载特定格式的文件。每个加载器都有一个唯一的名称,用于描述加载器将使用的文件类型。
public interface FileLoader {
void load();
}
在那之后,我们需要一个按需生产装载机的工厂。
@Component("Ext1")
public class Ext1FileLoader implements FileLoader {
public synchronized void load() {}
}
以下解决方案可能更简洁,但我们无法启用惰性初始化模式。看看:
@Component
public class FileLoaderFactory implements ApplicationContextAware {
// to get new loaders
private ConfigurableApplicationContext context;
// to keep already pulled out instances
private Map<String, FileLoader> loaders;
public FileLoader getFileLoaderByFileType(String type) {
// trying to use a lazy-loading mode
return loaders.get(type) == null ? getFromContext(type) : loaders.get(type);
}
private FileLoader getFromContext(String type) {
// getting a bean from the context, putting it into a map and returning a value
FileLoader loader = context.getBean(type, FileLoader.class);
loaders.put(type, loader);
return loader;
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
// a casting here is to get broader functionality from a context instance
this.context = (ConfigurableApplicationContext) context;
}
}
答案 1 :(得分:0)
定义工厂类以提供通用加载函数,如
public Class FileLoader {
//定义类似
的地图私人地图extensionToLoaderMap;
public static File load(StringfilePath){
//提取扩展并从Map
获取适当的加载器//在这里做一些有意义的事。
}
定义一个界面,例如
public interface ExtensionLoader {
public File loadExtension(String filePath);
}
现在您可以定义尽可能多的扩展加载器。
您可以使用您的DI框架来存储所有这些映射,例如here对于spring框架的描述
这将使您能够添加/修改扩展加载器的功能,而无需修改实际文件加载器的Java代码。