我有一个类,它在大型数据结构中包含一些细节,接受一个算法来对其执行某些计算,具有验证数据结构输入的方法。 但后来我想返回数据结构,以便可以通过View Model将其转换为各种输出形式(string / C#DataTable /自定义文件输出)。
class MyProductsCollection {
private IDictionary<string, IDictionary<int, ISet<Period>>> products;
// ctors, verify input, add and run_algorithm methods
}
我知道你应该使用&#34;依赖于接口而不是实现&#34;设计原则,所以我想为类创建一个接口。
如何避免编写以下界面? 原因是它会暴露实现细节并绑定任何其他具体实现以返回相同的表单。
interface IProductsCollection {
IDictionary<string, IDictionary<int, ISet<IPeriod>>> GetData();
// other methods
}
如何轻松地迭代数据结构以形成不同类型的输出而不会像这样直接暴露它?
编辑:
由于类在构造函数中接受IFunc<IDictionary<string, IDictionary<int, ISet<IPeriod>>>>
迭代数据结构并执行计算,我可以为它提供另一个IFunc
,它将构造输出而不是运行计算。但是,除了具体的类构造函数之外,我不知道如何做到这一点。
答案 0 :(得分:2)
IDictionary<string,IDictionary<int,ISet<Period>>>
的结构确实非常可疑 - 当你看到一本字典词典时,很可能你错过了一两个机会来创建一个封装内部词典的类。
在不了解您的问题的很多领域的情况下,我建议定义一个封装内部字典的接口。它看起来像是将一个数字与一组句点相关联的东西,所以你要定义一个这样的界面:
interface IYearlyPeriods {
bool HasPeriodsForYear(int year);
ISet<Periond> GetPeriodsForYear(int year);
}
我不知道这些时期的内容,因此您需要为界面选择特定于域的名称。
此外,您还可以包含下一级IDictionary
:
interface IProductDataSource {
IEnumerable<string> ProductNames { get; }
IYearlyPeriods GetProductData(string productName);
}
现在您可以定义这样的界面:
interface IProductsCollection {
IProductDataSource GetDataSource();
// other methods
}
主要思想是使用特定于域的接口来代替泛型集合,这样代码的读者和实现者就可以在不参考文档的情况下了解内部的内容。
您可以更进一步,并使用IDictionary
IDictionary
实施内部保留的复杂结构替换IProductPeriods
。如果您希望将IYearlyPeriods
保留给用户不可变的,但希望能够自己进行修改,则可以进行可变实现,并将其internal
保留到实现类中。
答案 1 :(得分:0)
我建议保持IDictionary
私有,并在界面中提供一个简单的IEnumerable
。
在你的情况下,这可能是一个隐藏IDictionary<int, ISet<IPeriod>>
的所有肮脏的自定义DTO - 这已经非常复杂,并且可能(可能)随着你需要实现新功能而轻易改变。
这可能是这样的:
class ExposedPeriod
{
public int PeriodIdentifier { get; set; }
public IEnumerable<IPeriod> Periods { get; set; }
}
ExposedPeriod
和PeriodIdentifier
可能需要更好的名字。您的域名词汇表中可能包含好名称。