我正在编写一些用于导入文件的代码,这些代码将根据描述文件布局的模板导入分隔或固定宽度的文件。
我创建了一个接口IFileTemplate:
public interface IFileTemplate
{
string Name { get; set; }
bool IgnoreEmptyLines { get; set; }
}
由DelimitedFileTemplate
类和FixedWidthFileTemplate
类使用。
我还有一个界面,用于指定构成模板的每个列:
public interface IFileTemplateColumn
{
int ID { get; set; }
string Name { get; set; }
bool Ignore { get; set; }
}
此接口随后由DelimitedTemplateColumn
类和FixedWidthTemplateColumn
类使用。
由于DelimitedFileTemplate和FixedWidthFileTemplate类都有一个列列表,我已使列表成为IFileTemplate列的成员:
List<IFileTemplateColumn> Fields { get; set; }
我的问题是当我来DelimitedFileTemplate和FixedWidthFileTemplate类中实现列表时,例如:
public class FixedWidthFileTemplate : IFileTemplate
{
public int ID { get; set; }
public string Name { get; set; }
public List<FixedWidthFileTemplateColumn> Fields { get; set; }
}
如果我尝试使用List<IFileTemplateColumn>
或List<DelimitedFileTemplateColumn>
实施List<FixedWidthFileTemplateColumn>
,则编译器会抱怨它们与List<IFileTemplateColumn>
不匹配。
我能理解这一点但是在ITemplateInterface中没有列列表似乎是错误的。我能想到的唯一解决方法是让Delimited和FixedWidth类使用List<IFileTemplateColumn>
并让属性getter将列表强制转换为分隔或固定宽度列列表,但似乎有一点代码味道。任何人都可以建议一个更好的方法吗?
答案 0 :(得分:1)
这个设计问题的合适且非臭的解决方案是泛型:
interface IFileTemplate<T> where T : IFileTemplateColumn
{
List<T> Fields { get; set; }
}
DelimitedFileTemplate
实施IFileTemplate<DelimitedFileTemplateColumn>
等等。
文件模板之间的所有差异可能仅由IFileTemplateColumn
合理定义,并且您可以使用FileTemplate<IFileTemplateColumn>
每个FileTemplateColumn类关系中的一个FileTemplate类进行简化。
<强>更新强>
对于工厂方法:IFileTemplate<IFileTemplateColumn> Create
:如果此方法的使用者应该能够访问列列表,则方法签名必须包含具体的ColumnTemplate。例如:
DelimitedFileTemplate Create
或强>
interface IFactory<T> where T : IFileTemplateColumn
{
IFileTemplate<T> Create();
}
class DelimitedFactory : IFactory<DelimitedFileTemplateColumn>
{
IFileTemplate<DelimitedFileTemplateColumn> Create()
{
return new DelimitedFileTemplate();
}
}
如果方法的使用者对列表不感兴趣,请引入更通用的界面(非常类似于IEnumerable<T> : IEnumerable
):
interface IFileTemplate { ... }
interface IFileTemplate<T> : IFileTemplate where T : IFileTemplateColumn
{
List<IFileTemplateColumn> Columns { get; set; }
}
然后,无论列如何,您的IFileTemplate Create()
方法都可以返回任何具体的FileTemplate。
我使用过这种泛型用法并且它们可能会传播(在此示例中,列层次结构将在FileTemplate层次结构中重复,并且可能在工厂层次结构中重复)。有时这会揭示设计中的一些缺陷。如果你能够明智地将IFileTemplate层次结构切割为一个基本的参数化FileTemplate类,那么这肯定是要走的路。这就是我经常使用的方法:定义最小的部分,如果层次结构倾向于复制,算法的某些部分可能会移动到“最小部分类”。