Java 处理多个文件格式的转换,避免耦合

Java 处理多个文件格式的转换,避免耦合,java,oop,design-patterns,Java,Oop,Design Patterns,我正在从事一个Java(RCP)项目,在该项目中,我需要将不同的源文件格式(我们称之为SF-1..N)转换为另外两种不同的目标格式(DF-a、DF-B) 现在输入文件可以是CSV、XLSX和XMLs(具有不同的模式)。应用程序应该找到正确的转换器,因此有必要读取文件内容。 每个转换器规范化文件的内容,并创建1..N个DF对象实例,这些DF对象被转换为DF-A或DF-B记录 因此,我有一些转换器,它们获取文件内容并返回DFs对象的集合。每个转换器还应该能够判断文件内容是否是它支持的内容 我能想到的

我正在从事一个Java(RCP)项目,在该项目中,我需要将不同的源文件格式(我们称之为SF-1..N)转换为另外两种不同的目标格式(DF-a、DF-B) 现在输入文件可以是CSV、XLSX和XMLs(具有不同的模式)。应用程序应该找到正确的转换器,因此有必要读取文件内容。 每个转换器规范化文件的内容,并创建1..N个DF对象实例,这些DF对象被转换为DF-A或DF-B记录

因此,我有一些转换器,它们获取文件内容并返回DFs对象的集合。每个转换器还应该能够判断文件内容是否是它支持的内容

我能想到的唯一策略是询问每个转换器是否支持文件内容,以及是否不尝试下一个转换器。如果没有合适的转换器,则向用户返回错误

我还可能被要求添加对新格式的支持,并且我希望能够添加更多转换器,而无需修改不必要的代码

我正在考虑在服务定位器对象中注册每个转换器,但我不确定如何以最小的耦合实现这一点。我曾考虑在静态初始值设定项中注册到服务定位器,但只有在加载类后才会调用它


我该怎么做?对于我想要实现的目标,有没有更好的方法?

在这种情况下,工厂设计看起来很合适

  • 制作一个描述转换器合同的接口
  • 为每种文件类型创建一个实现此接口的类
  • 创建受支持文件类型的枚举
  • 将枚举传递给工厂,并使其返回该文件类型的接口实现

公共抽象类DF{
//每个子类型的默认实现和抽象方法
}
公共类DF_A扩展DF{
}
公共类DF_B扩展DF{
}
公共最终枚举文件类型{
XML、CSV、XLSX;
}
公共接口文件转换器{
DF convert(最终URI文件位置);
}
类XMLConverter实现FileConverter{
@凌驾
公共DF转换(最终URI文件位置){
//将文件转换为DF并返回DF
}
}
//等等,适用于所有文件类型转换器
公共类FileConverterFactory{
私有静态映射文件_CONVERTER_Map=new HashMap();
静止的{
FILE_CONVERTER_MAP.put(FileType.XML,new XMLConverter());
//依此类推,适用于所有文件类型
//您可以使地图不可修改
FILE\u CONVERTER\u MAP=Collections.unmodifiableMap(FILE\u CONVERTER\u MAP);
}
公共静态最终DF转换(最终文件类型文件类型,最终URI文件位置){
返回文件\u CONVERTER\u MAP.get(文件类型).convert(文件位置);
}
}

如果客户端不知道文件类型,工厂可以修改如下:

public class FileConverterFactory {

    private static Map<FileType, FileConverter> FILE_CONVERTER_MAP = new HashMap<>();
    static {
        FILE_CONVERTER_MAP.put(FileType.XML, new XMLConverter());
        // And so on for all file types
        // You can make the map unmodifiable
        FILE_CONVERTER_MAP = Collections.unmodifiableMap(FILE_CONVERTER_MAP);
    }

    private static FileType getFileType(final URI fileLocation) throws UnsupportedFileFormatException {
        // Check file type and return enum as appropriate
    }

    // Client knows file type
    public static final DF convert(final FileType fileType, final URI fileLocation) {
        return FILE_CONVERTER_MAP.get(fileType).convert(fileLocation);
    }

    // Client doesn't know file type, let factory decide
    public static final DF convert(final URI fileLocation) throws UnsupportedFileFormatException {
        return convert(getFileType(fileLocation), fileLocation);
    }
}
公共类FileConverterFactory{
私有静态映射文件_CONVERTER_Map=new HashMap();
静止的{
FILE_CONVERTER_MAP.put(FileType.XML,new XMLConverter());
//依此类推,适用于所有文件类型
//您可以使地图不可修改
FILE\u CONVERTER\u MAP=Collections.unmodifiableMap(FILE\u CONVERTER\u MAP);
}
私有静态文件类型getFileType(最终URI文件位置)引发不支持的FileFormatException{
//检查文件类型并根据需要返回枚举
}
//客户端知道文件类型
公共静态最终DF转换(最终文件类型文件类型,最终URI文件位置){
返回文件\u CONVERTER\u MAP.get(文件类型).convert(文件位置);
}
//客户不知道文件类型,由工厂决定
公共静态最终DF转换(最终URI文件位置)引发不受支持的DFileFormatException{
返回convert(getFileType(fileLocation)、fileLocation);
}
}

M0skit0的答案很好,但考虑到客户端不知道文件的类型,我会让转换器接口实现CanConvert方法

然后,您可以简单地循环所有转换器,询问Then是否可以转换文件,并使用第一个可以转换的文件


这还有一个优点,即您可以动态添加新转换器,而无需更改枚举,因此可以在不重新编译应用程序的情况下添加新转换器

工厂应该有每个转换器的实例,对吗?工厂的客户不知道哪一个是正确的转换器,因为文件内容需要检查,这可能是转换器的责任。是的,您可以传递文件类型,也可以让工厂处理。如果文件类型不受支持,您可以抛出异常。我已经用一个示例扩展了我的答案,以防客户端不知道文件类型。请注意,
getFileType
方法具有开放式实现,这意味着您可以选择更适合自己的算法,包括Sam Holder的解决方案,方法是将
canConvert()
方法添加到
Converter
接口,或者让工厂检查类型并做出决定。或者您可以只信任文件扩展名。可能,但正如op所说,可以有几种不同模式的xml文件。对我来说,每个模式有一个转换器更有意义
public class FileConverterFactory {

    private static Map<FileType, FileConverter> FILE_CONVERTER_MAP = new HashMap<>();
    static {
        FILE_CONVERTER_MAP.put(FileType.XML, new XMLConverter());
        // And so on for all file types
        // You can make the map unmodifiable
        FILE_CONVERTER_MAP = Collections.unmodifiableMap(FILE_CONVERTER_MAP);
    }

    private static FileType getFileType(final URI fileLocation) throws UnsupportedFileFormatException {
        // Check file type and return enum as appropriate
    }

    // Client knows file type
    public static final DF convert(final FileType fileType, final URI fileLocation) {
        return FILE_CONVERTER_MAP.get(fileType).convert(fileLocation);
    }

    // Client doesn't know file type, let factory decide
    public static final DF convert(final URI fileLocation) throws UnsupportedFileFormatException {
        return convert(getFileType(fileLocation), fileLocation);
    }
}