尝试从缓存中获取数据,如果数据存在则返回,否则从数据源中获取数据,放入缓存,然后返回。
您是否熟悉上面这段逻辑说明?如果您的应用中大量使用了缓存,则上面这段逻辑很可能会出现许多次。例如:
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方法中。