尝试从缓存中获取数据,如果数据存在则返回,否则从数据源中获取数据,放入缓存,然后返回。
您是否熟悉上面这段逻辑说明?如果您的应用中大量使用了缓存,则上面这段逻辑很可能会出现许多次。例如:
CacheManager cacheManager = new CacheManager();
public List<User> GetFriends(int userId)
{
string cacheKey = "friends_of_user_" + userId;
object objResult = cacheManager.Get(cacheKey);
if (objResult != null) return (List<User>)objResult;
List<User> result = new UserService().GetFriends(userId);
cacheManager.Set(cacheKey, result);
return result;
}
这段逻辑似乎比较简单,不过在实际应用中,从数据源中获取数据可能不是简单地调用一个方法,而是需要多个类之间的协作,事务控制等等,而缓存的读写可能也会比上面的示例来的复杂。因此,一个可读性高的做法是提供三个独立的方法(读取缓存,读取数据源,写入缓存),使得一个拥有缓存的方法只需要简单地实现上面所提到的读写逻辑即可。
正如文章开头所说,如果您的应用中大量使用了缓存,则上面这段逻辑很可能会出现许多次。在一定程度上这种重复也是多余的,违背了DRY原则。因此我们设法提供一个基类,把这段缓存读写逻辑封装起来:
public abstract class CacheReader<T>
{
/// <summary>从缓存中获取数据</summary>
/// <param name="data">从缓存中取得的数据</param>
/// <returns>从缓存中成功取得数据则返回true,反之则false</returns>
public abstract bool GetFromCache(out T data);
/// <summary>从数据源获取数据</summary>
/// <returns>从数据源取得的对象</returns>
public abstract T ReadFromSource();
/// <summary>将数据写入缓存</summary>
/// <param name="data">将要写入缓存的数据</param>
public abstract void SetToCache(T data);
public T Read()
{
T data;
if (this.GetFromCache(out data)) return data;
data = this.ReadFromSource();
this.SetToCache(data);
return data;
}
}
于是我们将这段缓存读写逻辑集中到了CacheReader类的Read方法中。而对于每个缓存读写操作,我们只要实现一个CacheReader类的子类,提供三个抽象方法的具体实现即可。如下:
private class GetFriendCacheReader : CacheReader<List<User>>
{
private int m_userId;
private string m_cacheKey;
private CacheManager m_cacheManager;
public GetFriendCacheReader(int userId, CacheManager cacheManager)
{
this.m_userId = userId;
this.m_cacheKey = "friends_of_user_" + userId;
this.m_cacheManager = cacheManager;
}
public override bool GetFromCache(out List<User> data)
{
object objData = this.m_cacheManager.Get(this.m_cacheKey);
if (objData == null)
{
data = null;
return false;
}
data = (List<User>)objData;
return true;
}
public override List<User> ReadFromSource()
{
return new UserService().GetFriends(this.m_userId);
}
public override void SetToCache(List<User> data)
{
this.m_cacheManager.Set(this.m_cacheKey, data);
}
}
于是我们的GetFriends方法就可以修改成如下模样:
public List<User> GetFriends(int userId)
{
return new GetFriendCacheReader(userId, cacheManager).Read();
}
典型的“模板方法(Template Method)”模式的应