Previously I discussed about some places to put the Cache layer from an architectural point of view. The main ideas of that discussion are summarized as follows:

  • You have to encapsulate the cache access to prevent the ripple effect.
  • Placing the cache access within the UI Components, UI Process Components, Data Access Components or in Service Agents favor performance improvements.

Now I would like to review with greater detail how should the main class which accesses to the cache look like. That class should achieve the following goals:

  • Simplify the Get it if exists logic to read from it.
  • Isolate and restrict the usage of different cache providers.

There are different approaches for accessing the Cache. Some of them say Caching is a cross cutting concern, so It should be available from everywhere. Again, there is no only one answer; it depends on where you placed it first. I would say cloud applications which rely on caching services should choose the Service Agent to place the cache client. In other words, if you have a Visual C# project which is in charge of querying cloud data (that’s a Service Agent!) it’s a good idea to place the caching classes inside it, no other Visual C# projects should worry about what the underlying cache system is or re-writing the Get it if exists logic.

Having said that, your cache client class can be an abstract class with a concrete implementation of the Get it if exist logic. In fact this method it’s a template method which calls abstract/pure virtual methods in implementer classes to get the data. A sample implementation is described as follows.

   public abstract class CachedFilter
    {

        private ICacheable cache = null;
        private object _dataToPerfomTheQuery = null;

        public CachedFilter(object data)
        {
            _dataToPerfomTheQuery = data;
        }

        public void InjectCache(ICacheable newCache)
        {
            cache = newCache;
        }

        public abstract object ExecuteQuery(object pagingParams);
        public abstract string GetCacheKey(object dataToCreateTheCacheKey);

        public object Search(object dataToCreateTheCacheKey)
        {
            object cachedObj = cache.Get(GetCacheKey(dataToCreateTheCacheKey));
            if (cachedObj == null)
            {
                cachedObj = ExecuteQuery(_dataToPerfomTheQuery);
                cache.Set(GetCacheKey(dataToCreateTheCacheKey), cachedObj);
            }

            return cachedObj;
        }

        public object Get(object dataToCreateTheCacheKey)
        {
            return cache.Get(GetCacheKey(dataToCreateTheCacheKey));
        }

    }

As a software designer you should design these common packages/components so your team find easy implementing them, in that manner you should find easy the task distribution as well. I don’t like other implementations which add exotic elements to the design which in turn increases the complexity. By the way, the underlying cache system is injected implementing the strategy pattern.

[Update 08-Feb-2031: people in the memcached team implements the same solution that the previous sample http://bit.ly/NKhBSK]

Cheers,

Javier Andrés Cáceres Alvis

Microsoft Most Valuable Professional – MVP
Intel Black Belt Software Developer