2010-05-12 82 views
3

我有一个类别实体(类),它有零或一个父类别和许多子类别 - 它是一个树结构。类别数据存储在RDBMS中,因此为了获得更好的性能,我想加载所有类别并在启动应用程序时将它们缓存在内存中。我们的系统可以有插件,我们允许插件作者访问类别树,但他们不应该修改缓存的项目和树(我认为非只读设计可能会导致这个类库中的一些细微的错误),只有系统知道何时以及如何刷新树。寻找更好的设计:只读内存缓存机制

下面是一些演示代码:

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 
    } 
} 

到目前为止好。 但是,我想让ITreeNode接口可重复使用,对于其他一些类型,树不应只读。我们无法与上述只读ITreeNode要做到这一点,所以我想ITreeNode是这样的:

public interface ITreeNode<T> { 
    // has setter 
    T Parent { get; set; } 
    // use ICollection<T> instead of IEnumerable<T> 
    ICollection<T> ChildNodes { get; } 
} 

但是,如果我们做ITreeNode写,那么我们不能使分类树只读,这是不好。

所以我觉得,如果我们可以这样做:

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; } 
} 

这是好事还是坏事?有更好的设计吗?非常感谢! :)

回答

1

有一两件事你可以尝试是使用列表<牛逼>为您要为只读的IEnumerable的项目。然后,当您填充树结构时,您可以在内部调用您的列表上的AsReadOnly()方法,该方法将返回ReadOnlyCollection <T>并且您的数据的使用者将无法修改集合的内容。

这种方法并不只读但从接口的点,而是试图调用像的方法添加的收集将失败,并抛出一个异常。

为了保护您的其他成员,您可以在类的ITreeNode的实现类中创建一些专用只读标志,然后将您的标志设置为只读的缓存项目。

事情是这样的......


public class TreeNode : ITreeNode 
{ 
    private bool _isReadOnly; 
    private List<ITreeNode> _childNodes = new List<ITreeNode>(); 

    public TreeNode Parent { get; private set; } 

    public IEnumerable<ITreeNode> ChildNodes 
    { 
     get 
     { 
      return _isReadOnly ? _childNodes.AsReadOnly() : _childNodes; 
     } 
    } 
} 
+0

感谢。类别树应该是只读的,但在一些其他的例子中,例如,一个自定义的asp.net树控件,控制用户应该能够从树中添加/删除节点,所以树不应该是只读的。根据你的回答,我认为我们可以这样做: (1)使ITreeNode只读,也就是说,没有父节点的setter,并为ChildNodes返回IEnumerable 。 (2)对于Category Tree,我们使Category类实现ITreeNode,就像您在示例中所做的那样。(3)对于Tree Control,我们使用“new”关键字来隐藏ChildNodes属性,并让ChildNodes返回一个非只读集合。 对不对? – 2010-05-14 04:01:11

+0

@Dylan Lin - 是的,那可行。但是在Tree Control上,您应该让ChildNodes返回IEnumerable ,以便您可以根据实现控制对集合的访问。 – 2010-05-14 14:41:26

+0

我明白了。非常感谢。 – 2010-05-15 13:21:08