Java 基于标识符选择类的设计
我有一组数据解析器,它们实现了一个通用的Java 基于标识符选择类的设计,java,design-patterns,groovy,Java,Design Patterns,Groovy,我有一组数据解析器,它们实现了一个通用的DataSource接口。我想要一个具有以下签名的解析方法: public static DataSource parseData(InputStream contents, String identifier) 它应该获取要解析的数据和标识符,并使用适当的数据源实现。每个数据源负责一个标识符。我打赌有一种比这更优雅的方法: public static DataSource parseData(InputStream contents, String i
DataSource
接口。我想要一个具有以下签名的解析方法:
public static DataSource parseData(InputStream contents, String identifier)
它应该获取要解析的数据和标识符,并使用适当的数据源实现。每个数据源负责一个标识符。我打赌有一种比这更优雅的方法:
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的响应是受欢迎的 给定以下
数据源
类:
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 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] }
}
我知道BalRog的答案正是你想要的,但我忍不住抛出了一个反思性的答案 如果您确定您的标识符与类名相对应,例如,
idX
-->ParsersidX
,您可以这样做(免责声明-我没有编译这个-当然需要一些try/catch):
最后,我在评论中看到,这不是一对一的匹配,所以这种方式可能不够?你不能只使用
Map@mck,每个具体的数据源
子类是否有一个唯一的标识符
字符串,或者respondsTo
方法必须在可能无限(或至少非常大)的标识符字符串集合中找到某种模式吗?最多有三个唯一标识符。将来可能会更多,但肯定是一个可管理的数字。我考虑过使用映射,但从类对象实例化类对我来说总是有点恶心。@mck,每个子类最多有三个唯一标识符?还有一个问题,这些标识符字符串是计算机科学意义上的实际标识符吗?也就是说,标识符
字符串是否都作为变量名有效?对。这是一个多对一的匹配,但我认为您的答案可以进行调整,以给出该匹配,您只需要一种构建映射的方法。
DataSource parseData(InputStream contents, String identifier) {
DataSourceEnum.identify(identifier)?.buildDataSource(contents)
}
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);
}