嘗試從緩存中獲取數據,如果數據存在則返回,否則從數據源中獲取數據,放入緩存,然後返回。
您是否熟悉上面這段邏輯說明?如果您的應用中大量使用了緩存,則上面這段邏輯很可能會出現許多次。例如:
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);
}
}