Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 基于标识符选择类的设计_Java_Design Patterns_Groovy - Fatal编程技术网

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);
}