2014-01-31 113 views
1

我正在编写一些导入文件的代码,这些文件将根据描述文件布局的模板导入定界或固定宽度的文件。在接口内实现接口

我已经创建了一个接口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<DelimitedFileTemplateColumn>List<FixedWidthFileTemplateColumn>实现List<IFileTemplateColumn>那么编译器抱怨说,他们不匹配List<IFileTemplateColumn>

我可以理解这一点,但它似乎错误没有在ITemplateInterface列列表。我能想到的唯一方法就是让分隔符和固定宽度类使用List<IFileTemplateColumn>,并让属性getter将列表转换为分隔列或固定宽度列列表,但似乎有点代码味道。任何人都可以提出一个更好的方法来做到这一点

+0

如果您为已实现接口的类添加代码将会更好。它会更具可读性。 –

+0

@FaisalHafeez好的建议,现在更新。 – GrandMasterFlush

+0

我会退后一步,问为什么你有接口。是否有三个类实现每个接口,但除了对象之外没有公共基类? –

回答

1

一种合适的和无臭的解决这个设计问题是泛型:

interface IFileTemplate<T> where T : IFileTemplateColumn 
{ 
    List<T> Fields { get; set; } 
} 

DelimitedFileTemplate实现IFileTemplate<DelimitedFileTemplateColumn>等。

也许文件模板之间的所有差异只能由IFileTemplateColumn明确定义,并且您可以简化与每个FileTemplateColumn类关系中的一个FileTemplate类相关的FileTemplate<IFileTemplateColumn>

更新

至于工厂方法: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而不管该列。

我使用过这种泛型用法,它们可能会传播(在本例中,Column层次结构将在FileTemplate层次结构中复制,并可能在工厂层次结构中复制)。有时这会显示设计中的一些缺陷。如果你能够明智地将IFileTemplate层次结构切割为一个基本参数化的FileTemplate类,那肯定是一条可行的路。这就是我经常使用的方法:定义最小的部分,如果层次结构倾向于重复,那么算法的某些部分可能会转移到'最小部分类'。

+0

感谢您的回答,我发现在使用MVVM实施此解决方案时,您可以更轻松地使用第二条建议。如果列表包含不同类型的模板,则返回所有模板的列表将难以管理。 – GrandMasterFlush

+1

@GrandMasterFlush很高兴你能够自己解决这个问题。我终于有一段时间回到了这里 - 看到更新,我有类似的问题。 – lisp

+0

感谢您的更新,这给了我更多的东西来看看。干杯。 – GrandMasterFlush