我有一个Category实体(类),它有零个或一个父类别和许多子类别 - 它是一个树结构 . Category数据存储在RDBMS中,所以 for better performance, I want to load all categories and cache them in memory while launching the applicaiton.
我们的系统可以有插件,我们允许插件作者访问类别树,但是他们不应该修改缓存的项目和树(我认为非读取设计可能会导致这种情况下的一些微妙的错误),只有系统知道何时以及如何刷新树 .
以下是一些演示代码:
public interface ITreeNode<T>
where T : ITreeNode<T>
{
// No setter
T Parent { get; }
IEnumerable<T> ChildNodes { get; }
}
// This class is generated by O/R Mapping tool (e.g. Entity Framework)
public class Category : EntityObject
{
public string Name { get; set; }
}
// Because Category is not stateless, so I create a cleaner view class for Category.
// And this class is the Node Type of the Category Tree
public class CategoryView : ITreeNode<CategoryView>
{
public string Name { get; private set; }
#region ITreeNode Memebers
public CategoryView Parent { get; private set; }
private List<CategoryView> _childNodes;
public IEnumerable<CategoryView> ChildNodes {
return _childNodes;
}
#endregion
public static CategoryView CreateFrom(Category category) {
// here I can set the CategoryView.Name property
}
}
到现在为止还挺好 . However, I want to make ITreeNode interface reuseable, and for some other types, the tree should not be readonly . 我们无法使用上面的只读ITreeNode执行此操作,因此我希望ITreeNode如下所示:
public interface ITreeNode<T> {
// has setter
T Parent { get; set; }
// use ICollection<T> instead of IEnumerable<T>
ICollection<T> ChildNodes { get; }
}
But if we make the ITreeNode writable, then we cannot make the Category Tree readonly ,这不好 .
所以我想如果我们能这样做:
public interface ITreeNode<T> {
T Parent { get; }
IEnumerable<T> ChildNodes { get; }
}
public interface IWritableTreeNode<T> : ITreeNode<T> {
new T Parent { get; set; }
new ICollection<T> ChildNodes { get; }
}
Is this good or bad? Are there some better designs? Thanks a lot! :)
1 回答
您可以尝试的一件事是将 List<T> 用于您想要只读的IEnumerable项目 . 然后,当您填充树结构时,您可以在内部调用列表中的 AsReadOnly() 方法,该方法将返回 ReadOnlyCollection<T> ,并且您的数据的使用者将无法修改集合的内容 .
从接口的角度来看,这种方法不是 ReadOnly ,但尝试在集合上调用类似 Add 的方法会失败并抛出异常 .
为了保护您的其他成员,可以在类中的ITreeNode的实现类中构建一些私有只读标志,然后将您的标志设置为在缓存项目上只读 .
这样的东西......