据我所知,上下文模式是一种反模式。但是,我遇到了一个我需要解决的问题,可能会证明它的用法。这是上下文模式的有效参数吗?
我有一组类实现IParser
。 IParser
接口要求实现者可以实现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
implementsIFieldLocator<CsvFile>
and it'sGetField(string fieldReference, CsvFile input)
方法是一个包装以访问CsvFile.GetField(int lineNumber, int columnNumber)
。fieldReference
中的字符串是类似excel的列/行引用。CsvParser
在它的构造函数中需要一个IFieldLocator<CsvFile>
。
这就是我解决这个问题的方法。不过,我仍然有兴趣看到你的意见。