用于创建用于缓存对象的单例字典的模式

时间:2017-06-28 05:14:15

标签: c# dictionary

我正在尝试为对象创建缓存机制。而我将创建一种工厂方法来创建对象并在字典中跟踪现有对象。所以,如果一个对象存在于字典中,我可以简单地返回它。如果该对象不存在,那么我可以实例化一个,将其添加到字典中,然后返回它。

基本上,我正在创建一个单身人士字典,可以这么说。我显然可以尝试坚持为每种类型创建单例,然后创建一个字典。我想知道是否有更好的方法来解决它,因为我目前的单身人士字典计划并不是那么有效。

2 个答案:

答案 0 :(得分:1)

我给你一个想法,你可以使用各种各样的添加或删除该类的部分: 您缓存了一些对象(如果您需要,该数量可能会受到限制

  

容量)

最好使用2种结构:

  

LinledList和Dictionary(检索成本O(1))

您将缓存的对象保留在Dictionary中,当您需要再添加一个对象时,将其添加到Dictionary和LinkedList的末尾,当您获得最大容量时,您将从LinkedList中删除第一个对象,并从中删除相同的对象。字典能够添加一个新的。当您想要使用某个对象时,只需将其返回并将其在LinkedList中移动到最后。

因此,您可以在Dictionary中跟踪现有对象而不重复,并且您在LinkedList中获得缓存对象的“队列”,其中LinkedList的末尾是最后使用的对象。您可以根据需要实例化对象 - 为简单起见,我使用Item构造函数进行实例化。

public class Item
{
    public string key;
    public object obj;
    public Item(string k, object o) { k = key; o = obj; }
}
class MyCache
{
    LinkedList<Item> ll = new LinkedList<Item>();
    LinkedListNode<Item> node;
    Dictionary<string, LinkedListNode<Item>> dd = new Dictionary<string, LinkedListNode<Item>>();
    int capacity = 5;     //just for simplicity set capacity for caching

    //here you Add new object
    public void Add(string key, object obj)
    {
        if (cap == 0) return; 
        //check if you already have that object
        if (!dd.TryGetValue(key, out node)) 
        {
            //if capacity exceeded- remove object from beginig of LinkedList
            if (dd.Count >= capacity) 
                RemoveItem();
            Item item = new Item(key, obj);
            LinkedListNode<Item> newNode = new LinkedListNode<Item>(item);
            ll.AddLast(newNode);
            dd.Add(key, newNode);
            return;
        }
        //we move that object to the end of the list
        ll.Remove(node);
        ll.AddLast(node);
    }

    // remove object from LinkedList and Dictionary
    void RemoveItem()
    {
        LinkedListNode<Item> node = ll.First;
        ll.Remove(node);
        dd.Remove(node.Value.key);
    }

    public object Get(string key)
    { 
        //if we have that object, we return it and move to the end of LList           
        if (dd.TryGetValue(key, out node))
        {
            ll.Remove(node);
            ll.AddLast(node);
            return node.Value.obj;
        }
        else return default(object);
    }
}

答案 1 :(得分:0)

这是我自己使用的可靠缓存解决方案。主要想法很简单。 利用拦截器是一种有效的解决方案。拦截器将决定从缓存中检索数据或进行服务调用。 解决方案由三个不同的部分组成。第一部分是一个高度封装的存储库,它至少有四种主要的通用方法,用于注入,获取和消除(全部或特定)。如您所见,代码保证存储库中不存在冗余对象。

简单存储库

 public static class Repository
    {
        private static Dictionary<Type, object> _dictionary;
        static Repository()
        {
           _dictionary=new Dictionary<Type, object>(); 
        }

        public static T ReadRepository<T>()
        {
            var type = typeof (T);
            object item;
            var result = _dictionary.TryGetValue(type, out item);
            if (!result) return default (T);
            return (T)Convert.ChangeType(item, typeof(T));
        }

        public static void InjectRepository<T>(object value)
        {
            var type = typeof(T);
            object item;
            var result = _dictionary.TryGetValue(type, out item);
            if(result)return;
            _dictionary.Add(type, value);
        }

    }

在第二部分中,您需要创建一个名为[Cache]的自定义属性。您的逻辑方法需要使用此属性进行修饰。例如,您有一个fetch方法,它进行服务调用以实现所需的数据。使用此属性,Interceptor将决定从缓存中检索信息或让方法进行服务调用。

逻辑方法

[Cache]
public User FetchUser(string userId)
{
  //...
}

突出的一点是,您不能直接调用逻辑方法。拦截器将完成这一部分。实现可以利用的拦截器有不同的机制和模式。看下面的代码。使用委托理念,我已经成为了自己的执行者。

public delegate User UserDelegation(string userID);

一个简单的拦截器

 public static object Executor(UserDelegation delegation)
 {
  // If it is decorated witch [Cache] attribute, Fetch data from cache
  // Else
  delegation.Invoke(userId);
  //...
 }