寻找更好的设计:只读内存缓存机制

时间:2010-05-12 04:11:20

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

我有一个Category实体(类),它有零个或一个父类别和许多子类别 - 它是一个树结构。类别数据存储在RDBMS中,所以为了获得更好的性能,我想在启动应用程序时加载所有类别并将它们缓存在内存中。

我们的系统可以有插件,我们允许插件作者访问类别树,但是他们不应该修改缓存的项目和树(我认为非readonly设计可能会在这个场景中引起一些微妙的错误),只有系统知道何时以及如何刷新树。

以下是一些演示代码:

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 个答案:

答案 0 :(得分:1)

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

从界面的角度来看,这种方法不是 ReadOnly ,但尝试在集合上调用添加等方法会失败并抛出异常。< / p>

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