Лично я в настоящее время использую NHibernate, который обрабатывает кеширование для вас. В прошлом я делал нечто похожее на то, что вы пытаетесь сделать, однако мне никогда не приходилось отделять слой кэширования от слоя дао. Есть ли какая-то причина, по которой вам нужно отделить их? Я полагаю, что это имело бы смысл, если у вас существенно разные потребности в кэшировании в зависимости от типа объекта. Во всяком случае, если предположить, что это необходимо, вот как я буду делать это на основе прошлого опыта. Во-первых, давайте предположим, что у нас есть следующие классы: PersistentObject, который является базовым объектом, у которого есть хотя бы целочисленное свойство с именем "ID"
public class PersistentObject
{
public int ID { get; set; }
}
Теперь скажите, что у вас есть тип выборки, который вы хотели бы сохранить:
public class SampleObject : PersistentObject
{
public string SomeValue { get; set; }
}
Вместо «DataProvider» у меня есть простой интерфейс хранилища:
public interface IRepository<T> where T : PersistentObject
{
T Get(int id);
void Save(T e);
void Delete(T e);
}
Как насчет того, чтобы вместо вашего интерфейса IDataManager у вас был абстрактный класс, который вы можете реализовать, который является хранилищем, которое обрабатывает кэширование (у меня есть свой собственный класс "CacheManager", который я здесь использую, он может быть реализован любым числом путей):
public abstract class CacheRepository<T> : IRepository<T> where T : PersistentObject
{
private const string CacheKeyPrefix = "RepoCache-";
private string GetCacheKey(int id)
{
return CacheKeyPrefix + typeof(T).FullName + "-" + id.ToString();
}
public T Get(int id)
{
string cacheKey = GetCacheKey(id);
T obj = CacheManager.GetItemFromCache<T>(cacheKey);
if (obj == null)
{
obj = this.GetData(id);
if (obj != null)
CacheManager.AddItemToCache(obj, cacheKey);
}
return obj;
}
public void Save(T obj)
{
string cacheKey = GetCacheKey(obj.ID);
this.SaveData(obj);
CacheManager.AddItemToCache(obj, cacheKey);
}
public void Delete(T obj)
{
string cacheKey = GetCacheKey(obj.ID);
this.DeleteData(obj);
CacheManager.RemoveItemFromCache(cacheKey);
}
protected abstract T GetData(int id);
protected abstract void SaveData(T obj);
protected abstract void DeleteData(T obj);
}
Вы заметите, что единственные открытые члены - это методы, реализующие IRepository. Существует 3 абстрактных метода, которые должны быть реализованы для доступа к данным отдельным репозиторием. Таким образом, мы можем сделать это здесь для нашего SampleObject:
public class SampleObjectRepository : CacheRepository<SampleObject>
{
protected override SampleObject GetData(int id)
{
//do some loading
return new SampleObject();
}
protected override void SaveData(SampleObject obj)
{
//do some saving
}
protected override void DeleteData(SampleObject obj)
{
//do some deleting
}
}
Наконец, вот как вы будете использовать этот код:
public class UsageSample
{
public UsageSample()
{
//save a new object
SampleObjectRepository repo = new SampleObjectRepository();
SampleObject sampleObj = new SampleObject();
repo.Save(sampleObj);
//load an object by ID
int id = sampleObj.ID;
sampleObj = repo.Get(id);
//delete an object
repo.Delete(sampleObj);
}
}
Это становится значительно сложнее, когда вы начинаете говорить о возврате коллекций и запросах, но это, по крайней мере, упрощенное начало. Вы уверены , что вас не интересуют сторонние решения? :-) NHibernate отлично справляется со всем этим.