2014-01-16 26 views
1

据我所知,上下文模式是一种反模式。但是,我遇到了一个我需要解决的问题,可能会证明它的用法。这是上下文模式的有效参数吗?

我有一组类实现IParserIParser接口要求实现者可以实现CanRead(Stream)--实现者返回是否推导出Stream是否以适当的格式读取。因此,例如,CsvParser会读取该流并检查它是否满足正则表达式([\w]*),

接下来,他们必须实现Parse(Stream),其中实现者将采用Stream并以自己的方式解析它,只要它们从其解析的数据返回可枚举的POCO。

现在,这里是擦。有几个解析器 - 例如XmlParser,CsvParser等。每个解析器都知道如何解析它自己的格式,但数据来自第三方用户。我们不能保证他们的数据布局符合每个解析器的预期。也就是说,虽然他们很可能是在有效的XML或CSV,他们可能没有相同的字段名称将数据映射(一个源可能有<DateTime>...</DateTime>,另外可能有<Time>...</Time>)等

我不想必须为每个可能略有变化的客户编写解析器。 要解决这个问题,我建议我有一个可以作为“地图”的类。这将具有将被命名为期望的字段名称的属性,并且具有该字段的实际字段名称/位置的值(根据Csv文件,它将是该列)。这将传递给Parse(Stream)方法。

但是,据我所知,这是上下文模式。更何况,它在解析器类上承担了额外的责任,因为它不仅需要读取文件,还必须将输入映射到输出。从测试的角度来看,这也是一种非常难看的方式。有没有更好的方法来解决这个问题?

编辑: 在真正的测试驱动的开发方式,我想出了一个解决方案,看起来是这样的:现在

  • IParser的解析方法是Parse(Stream stream, string dateReference, string valueReference, string idReference)
  • 用方法GetField(String fieldReference, T input)创建一个名为IFieldLocator<T>的新接口。

现在对于实现:

  • CsvFile是一个值对象,发生在它的构造一个CSV字符串,并允许您通过GetField(int lineNumber, int columnNumber)访问它。
  • CsvFieldLocator implements IFieldLocator<CsvFile> and it's GetField(string fieldReference, CsvFile input)方法是一个包装以访问CsvFile.GetField(int lineNumber, int columnNumber)fieldReference中的字符串是类似excel的列/行引用。
  • CsvParser在它的构造函数中需要一个IFieldLocator<CsvFile>

这就是我解决这个问题的方法。不过,我仍然有兴趣看到你的意见。

回答

0

重申发布您的问题:

  1. 你有一个CSV解析器解析CSV的一个特定的格式,并返回一些有用的东西,并解析XML的特定格式,并返回一些有益的XML解析器。
  2. 您正在接收包含等效数据但格式不同的CSV和XML流。
  3. 您对这些格式的差异有所了解(大概是否则您将无法创建您建议的上下文对象)。

所以,你有个好解析器和良好的流,但你一个间隙,因为良好的解析器不是良好的流了良好的解析器。

我不会通过传递上下文来改变解析器,我会弥补差距。

有两个地方可以做到这一点。

首先,由于针对特定目标的精心设计的XML或CSV解析器将建立在一般XML或CSV解析器之上,所以我们可以在中间放置一些东西。使用CSV很容易(例如,如果一般解析器为每行提供了string[]的枚举,那么我们可以移动字段并可能重新格式化一些),但是通常用XML更复杂(您当然可以编写一个从XmlReader派生的类,说当地的名字是Time,当时它的来源XmlReader说它是DateTime,但这很讨厌)。

第二种是将流本身转换为符合所需格式的流。这在XML中很容易(只需使用XSLT,并且每个源只需要一个不同的XSLT模板),而且CSV也有点棘手,尽管远非火箭科学。

我建议这第二种方法。

除了其他事情之外,调试比上下文对象更容易:如果上下文对象设置不正确,那么在解析器深处的某个地方,一件事会被错误地重新映射,或者根本没有被重新映射错误与实际的解析混合在一起。如果用于重新格式化代码的过滤器存在缺陷,那么它不会根据给定的输入生成正确的格式,而是可以在完全隔离的情况下对其进行解析。

基于此,您可以进一步简化您的解析:如果您正在重新格式化流,为什么需要两个解析器?从给定的XML输入中生成CSV的XSLT并不重要,用CSV生成给定XML格式的代码也非常简单。基于代码维护的容易程度,以及您必须处理的流中特定格式的频率以及添加一个过滤器或一系列过滤器来弥合差距,从而解决一个解析器问题。

XSLT当然不是将一个XML流转换成另一个XML流的唯一方式,但它具有无需重新编译即可轻松修改的优点,如果您需要添加更多格式,或者您的某个源更改其格式某种方式。