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

时间:2015-03-21 13:21:04

标签: java oop design-patterns

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

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

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

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

我正在考虑在服务定位器对象中注册每个转换器,但我不知道如何以最小的耦合来做到这一点。我考虑过在静态初始化程序中注册服务定位器,但只在加载类后才会调用它。

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

2 个答案:

答案 0 :(得分:2)

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

然后你可以简单地遍历所有转换器,询问是否可以转换文件并使用第一个可以。

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

答案 1 :(得分:1)

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

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

public abstract class DF {
     // Default implementation and abstract methods for each subtype
}

public class DF_A extends DF {
}

public class DF_B extends DF {
}

public final enum FileType {
    XML, CSV, XLSX;
}

public interface FileConverter {
    DF convert(final URI fileLocation);
}

class XMLConverter implements FileConverter {
    @Override
    public DF convert(final URI fileLocation) {
        // Convert file to DF and return DF
    }
}

// And so on for all the file type converters

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

    public static final DF convert(final FileType fileType, final URI fileLocation) {
        return FILE_CONVERTER_MAP.get(fileType).convert(fileLocation);
    }
}

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

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