在接口中实现接口

时间:2014-01-31 11:56:40

标签: c# interface

我正在编写一些用于导入文件的代码,这些代码将根据描述文件布局的模板导入分隔或固定宽度的文件。

我创建了一个接口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将列表强制转换为分隔或固定宽度列列表,但似乎有一点代码味道。任何人都可以建议一个更好的方法吗?

1 个答案:

答案 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类,那么这肯定是要走的路。这就是我经常使用的方法:定义最小的部分,如果层次结构倾向于复制,算法的某些部分可能会移动到“最小部分类”。