使用策略模式的Java通用文件解析器设计


14

我正在开发一种产品,其中一个模块的职责是解析XML文件并将所需内容转储到数据库中。即使目前的要求只是解析XML文件,我仍希望以一种将来可以支持任何类型文件的方式设计解析模块。采用这种方法的原因是,我们正在为特定客户生产该产品,但计划在不久的将来将其出售给其他客户。当前客户端的生态系统中的所有系统都会生成和使用XML文件,但其他客户端可能并非如此。

到目前为止,我尝试了什么?(现在) 我想到的是基于策略模式的以下设计。我很快就用eclipse编写了代码以传达我的设计,因此,如果暂时忽略其他方面(如正确的异常处理方式),那将是很好的选择。

Parser:公开解析方法的策略接口。

 public interface Parser<T> {
        public T parse(String inputFile);
    }

*使用泛型参数的原因是允许任何返回类型以及在编译时确保类型安全。

ProductDataXmlParser一个具体类,用于解析包含产品相关信息的product.xml文件。(使用XMLBeans)

public class ProductDataXmlParser implements Parser<ProductDataTYPE> {

    public ProductDataTYPE parse(String inputFile) {
        ProductDataTYPE productDataDoc = null;
            File inputXMLFile = new File(inputFile);

        try {
            productDataDoc = ProductDataDocument.Factory.parse(inputXMLFile);
        } catch(XmlException e) {
            System.out.println("XmlException while parsing file : "+inputXMLFile);
        } catch(IOException e) { 
                 System.out.println("IOException while parsing file : "+inputXMLFile);
        }
        return productDataDoc.getProductData();
    }
} 

其中:ProductDataTYPE和ProductDataDocument是使用xsd和scomp命令生成的XMlBean POJO类。

未来

如果将来有要解析的product.txt文件,则可以定义自己的POJO(称为ProductData),该POJO将保存文件的所需内容。然后,我可以创建一个名为ProductDataFlatFileParser的具体类,该类实现解析器接口,并在解析文件后让parse方法为我填充ProductData POJO。

这种设计有意义吗?此设计是否有任何明显的缺陷?按照设计的观点,我允许具体类定义解析文件的算法,并让具体类决定填充数据的位置。设计似乎更依赖于域对象,而不是文件格式。这是坏事吗?任何有关如何改进设计的意见都将受到高度赞赏。


该软件是否应该不让调用者知道支持哪些文件格式?您的软件如何知道要调用哪个解析器?
tomdemuyt

您正在寻找有关您的设计的反馈,而不是您的实际实现,因此它将被移植到程序员那里。
–codesparkle

@tomdemuyt 认为工厂模式;)
CKing 2013年

2
@bot告诉您将其发布到Code Review上的SO用户显然是错误的。您可以在发布网站之前阅读该网站的常见问题解答,“有人告诉我这样做”并不是您要做任何事情的充分理由。没有人在打乒乓球,有人自愿花时间为它找到一个更好的地方,而不是直接关闭它(这是一个有效的选择,因为它不在Code Review的讨论范围之内)。
yannis

2
也请不要交叉张贴。您搞砸了,我们必须清理。
扯掉

Answers:


7

我有几个问题:

  1. 我会确保在实施之前,您实际上需要通用设计。您确定要使用XML以外的其他文件类型吗?如果没有,为什么要为它们编码?如果最终需要它,则可以在那时修改代码。不会花太多时间,您可能还会有其他要求,这些要求将使代码看起来与当前建议的有所不同,并且您可能永远也不需要编写它。正如他们所说,YAGNI(您将不需要它)。
  2. 如果您确实需要通用设计,并且对此非常确定,那么我认为这Parser<T>基本上是合理的。我确实看到了两个潜在的问题:(1)它假定文件输入-例如,如果您尝试解析从HTTP响应中检索到的JSON流,该怎么办?(2)它不一定提供很大的价值,只是作为一个较大的通用框架的一部分,在该框架中,您可以针对许多不同类型的数据使用许多不同类型的解析器。但是我不认为您需要任何如此大的通用框架。据我所知,您现在只有一个非常简单,具体的用例:将XML文件解析为ProductDatas 的列表。
  3. 像处理in一样,吞没异常几乎不是一个好主意ProductDataXmlParser。我会将其转换为某种形式RuntimeException

1
我们正在开发一种可以与许多外部系统通信的产品,因此我认为考虑任何类型的文件/输入格式都是一个好主意。关于JSON Stream的要点。这就是为什么我在Parser接口中的parse方法使用String参数而不是File参数的原因。我已经更正了我的ProductDataXmlParser中的一个小错误(需要将文件传递给XmlBean解析器)。吞下异常也很正确。我很快在eclipse中写下了这段代码,以通过一个示例来传达我在stackoverflow上的设计;)
CKing 2013年

好的。我想我要说的是将Parser参数设为InputStream而不是String。:)很高兴听到有关该异常的信息-我不确定是从您的实际代码中还是从StackOverflow的示例代码中粘贴了该内容。

1
另外,关于构建将与许多外部系统通信的产品,我会犹豫是否要构建没有具体要求的通用代码。例如,在您至少需要解析两种类型的对象或两种文件格式之前,我不会创建通用的Parser接口。

我会考虑你在说什么。我想指出的是,有4个不同的xml文件包含要解析的4种不同类型的数据。产品数据只是我们的系统/产品要使用的一种数据类型。
CKing

我还有一个问题要问你。我不会使用作​​为策略模式一部分的上下文。这样可以吗?我还摆脱了通用参数,并在Parser接口的parse方法中返回了Object。这是为了避免使用解析器的类通过类型参数声明。
2013年

1

您的设计不是最佳选择。根据您的设计,使用它的唯一方法是:

ProductDataXMLTYPE parser = new ProductDataXmlParser<ProductDataXMLTYPE>().parse(input); 
ProductDataTextTYPE parser = new ProductDataTextParser<ProductDataTextTYPE >().parse(input);

从上面的示例中我们看不到太多好处。我们不能做这样的事情:

Parser parser = getParser(string parserName);
parser.parse();

在寻求泛型之前,可以考虑以下两个选项:

  • 1,解析后输出相同

无论数据源来自何处,产品数据在保存到数据库之前都将具有相同的格式。这是客户与转储服务之间的合同。因此,我假设您具有与输出相同的ProductData。您可以简单地定义一个接口:

public interface Parser {
    public ProductData parse(String inputFile);
}

此外,如果您想更灵活地将ProductData定义为接口。

如果您不希望解析器与数据混合在一起。您可以将其拆分为两个接口:

public interface Parser {
     public void parse(String inputFile);
}
public interface Data {
    public ProductData getData();
}

您的解析器将如下所示:

public class XMLParser implements Parser, Data {} 
public class TextParser implements Parser, Data {}
  • 2,解析后输出不同

如果ProductData不相似,并且您确实想重用Parser接口。您可以这样进行:

public interface Parser {
   public void parse(String inputFile);
}

class XMLParse implements {
      @Override
      public void parse(String inputFile);

      ProductDataXML getProductData();        
}

class TextParse implements {
      @Override
      public void parse(String inputFile);

      ProductDataText getProductData();        
}

-2

以防万一您希望使用已经可用的东西,我制作了一个名为JRecordBind的Java库,该库基于XMLSchema(由JAXB支持)。

它诞生于消耗/产生固定长度的文件,并且由于XMLSchema定义了它们的结构,因此可以将其与普通JAXB一起使用来编组/解组XML文件。


我正在寻找一种实现通用解析器的设计!我认为您不能正确理解我的问题。:)
13年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.