我有一组实现公共DataSource
接口的数据解析器。我想要一个具有以下签名的解析方法:
public static DataSource parseData(InputStream contents, String identifier)
它应该使用要解析的数据和标识符并使用适当的DataSource实现。每个DataSource负责一个标识符。我敢打赌,有一种比这更优雅的方式:
public static DataSource parseData(InputStream contents, String identifier) {
if (DataSource1.respondsTo(identifier) {
return new DataSource1(contents);
}
//more ifs. There likely will be about 20 of those.
}
但我真的无法想到更好的事情。这里有适当的设计模式吗?某种链式探测器列表?
我在Groovy中这样做,但欢迎基于Java的响应。
答案 0 :(得分:3)
给出以下DataSource
类:
interface DataSource {
boolean respondsTo(String identifier)
}
class DataSource1 implements DataSource {
DataSource1(InputStream is) { /* magic goes here */ }
@Override boolean respondsTo(String identifier) { identifier in ["DS1 idX", "DS1 idY", "DS1 idZ"] }
}
class DataSource2 implements DataSource {
DataSource2(InputStream is) { /* magic goes here */ }
@Override boolean respondsTo(String identifier) { identifier in ["DS2 idX", "DS2 idY", "DS2 idZ"] }
}
// ...
class DataSource20 implements DataSource {
DataSource20(InputStream is) { /* magic goes here */ }
@Override boolean respondsTo(String identifier) { identifier in ["DS20 idX", "DS20 idY", "DS20 idZ"] }
}
此解决方案使用enum
来帮助将每个identifier
字符串映射到生成DataSource
的闭包中。
enum DataSourceEnum {
ds1 (["DS1 idX", "DS1 idY", "DS1 idZ"], { is -> new DataSource1(is) }),
ds2 (["DS2 idX", "DS2 idY", "DS2 idZ"], { is -> new DataSource2(is) }),
// ...
ds20 (["DS20 idX", "DS20 idY", "DS20 idZ"], { is -> new DataSource20(is) })
private final static Map<String, DataSourceEnum> dsMapping = [:]
final Closure<DataSource> buildDataSource
private DataSourceEnum(List<String> identifiers, Closure<DataSource> ctor) {
DataSourceEnum.dsMapping += identifiers.collectEntries { id -> [(id):this] }
this.buildDataSource = ctor
}
static DataSourceEnum identify(String id) { dsMapping[id] }
}
现在编写所需的parseData
方法几乎非常简单:
DataSource parseData(InputStream contents, String identifier) {
DataSourceEnum.identify(identifier)?.buildDataSource(contents)
}
答案 1 :(得分:0)
我意识到BalRog的答案就是你想要的,但我忍不住抛出一个反思的答案。
如果您确定与类名相对应的标识符,例如idX
- &gt; ParsersidX
,你可以这样做(免责声明 - 我没有编译这个 - 肯定有一些尝试/捕获必要):
public static DataSource parseData(InputStream contents, String identifier) {
Class dataSourceClass = Class.forName("Parsers" + identifier);
Constructor dataSourceConstructor = dataSourceClass.getDeclaredConstructor(Class.forName(InputStream));
return dataSourceConstructor.newInstance(contents);
}
最后,我在评论中看到,这不是一对一的比赛,所以这种方式可能不够?