通用延迟加载缓存类






3.25/5 (4投票s)
提供了一个用于创建单例延迟加载缓存的基础类。
引言
这个通用类可以被继承,并用作延迟加载对象的简单内存缓存。
背景
在我的应用程序中,我注意到我经常实现一个延迟加载缓存。我将其用于从数据库加载的静态或近乎静态的数据,并且我不想在对象图中多次拥有这些数据。
该类的要求是:
- 仅加载对象一次。 初始加载后,对该对象的请求将返回已在内存中的副本(即延迟加载)。
- 缓存的单例模式,确保只有一个实例。
- 通过键对象检索对象(字典)。
- 派生类负责对象的初始加载。
做过几次之后,我认为我可以使用泛型来创建一个可重用的缓存基类。 我想使用模板模式,以便每个派生类实现自己的加载机制,并将其与单例模式结合起来。
Using the Code
要使用此代码,只需从基类继承即可。 派生类需要一个私有/受保护的构造函数,以确保无法直接实例化它,并且需要重写 GetItem 成员才能在对象不在缓存中时实际从某个位置获取该对象。
必须提供三种类型:
- T:继承 LazyLoadCacheBase 类的类的类型。
- TKey:键的类型。
- TValue:存储在缓存中的对象的类型。
这是该类:
/// <summary>
/// This base class can be inherited to implement a lazy load cache
/// </summary>
/// <typeparam name="T">Pass in the type of the derived class (the type of the class that
/// inherits this base class)</typeparam>
/// <typeparam name="TKey">Type of the dictionary key objects</typeparam>
/// <typeparam name="TValue">Type of the dictionary value objects</typeparam>
internal abstract class LazyLoadCacheBase<T, TKey,
TValue> where T: LazyLoadCacheBase<T, TKey, TValue>
{
private Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();
abstract protected TValue GetItem(TKey key);
protected LazyLoadCacheBase()
{
}
public static T Instance
{
get
{
return Creator.Singleton;
}
}
public Dictionary<TKey, TValue> Dictionary
{
get { return _dictionary; }
set {_dictionary = value;}
}
public TValue GetValue(TKey key)
{
if (!_dictionary.ContainsKey(key))
{
TValue item = GetItem(key);
_dictionary.Add(key, item);
}
return _dictionary[key];
}
private sealed class Creator
{
private static readonly T _instance = (T)typeof(T).InvokeMember(typeof(T).Name,
BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Instance,
null, null, null);
internal static T Singleton
{
get { return _instance; }
}
}
}
使用该类的一个例子:
internal class MyObjectCache: LazyLoadCacheBase<MyObjectCache, int, IMyObject %gt;
{
// Prevent direct instantiation
private MyObjectCache()
{
}
protected override IMyObject GetItem(int key)
{
IMyObject item = GetMyObjectFromDB(key);
return item;
}
}
关注点
- 为了维护派生类作为单例,它们需要具有私有或受保护的构造函数。 这就需要在实例化单例时使用反射。
- 在我的实现中,我公开了内部字典,以防我想一次加载所有项目,并提供灵活性。 所需的功能实际上应该被封装(例如,LoadAll 方法)。
- 我故意保持这个类非常简单。 如果您有其他要求,应该很容易自己添加它们。 例如,加载到缓存中的项目会一直保留到应用程序关闭。 显然,您可以包含一种基于过期时间或其他标准从缓存中删除项目的机制。
历史
- 首次提交。