【问题标题】:Looking for a better design: A readonly in-memory cache mechanism寻找更好的设计:只读内存缓存机制
【发布时间】:2010-05-12 04:11:20
【问题描述】:

我有一个类别实体(类),它有零个或一个父类别和许多子类别——它是一个树结构。类别数据存储在 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 可写,那么我们就不能让 Category Tree 只读,那就不好了。

所以我想如果我们可以这样做:

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

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

【问题讨论】:

    标签: c# .net design-patterns tree readonly


    【解决方案1】:

    您可以尝试的一件事是将 List 用于您希望只读的 IEnumerable 项目。然后,当您填充树结构时,您可以在内部调用列表中的 AsReadOnly() 方法,该方法将返回 ReadOnlyCollection 并且您的数据的消费者将无法修改集合的内容。

    从界面的角度来看,这种方法不是 ReadOnly,但尝试在集合上调用 Add 之类的方法会失败并引发异常。

    为了保护其他成员,您可以在类内的 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;
            }
        }
    }
    

    【讨论】:

    • 谢谢。类别树应该是只读的,但在其他一些场景中,例如,自定义 asp.net 树控件,控件用户应该能够从树中添加/删除节点,因此树不应该是只读的。根据您的回答,我认为我们可以这样做:(1)​​将 ITreeNode 设为只读,即 Parent 没有设置器,并为 ChildNodes 返回 IEnumerable。 (2) 对于 Category Tree,我们让 Category 实现 ITreeNode 就像您在示例中所做的那样。 (3) 对于Tree Control,我们使用“new”关键字隐藏ChildNodes属性,让ChildNodes返回一个非只读集合。对吗?
    • @Dylan Lin - 是的,这行得通。但是在树控件上,您应该让 ChildNodes 返回 IEnumerable 以便您可以根据实现控制对集合的访问。
    猜你喜欢
    • 2013-01-12
    • 1970-01-01
    • 2010-10-09
    • 1970-01-01
    • 2012-07-10
    • 2010-09-24
    • 1970-01-01
    • 2018-02-14
    相关资源
    最近更新 更多