Recently, one of my colleagues stated that the cache should always be required dependency. We should require it in non-null constructor parameter. And we can’t use null-object pattern with it.
How to bring over this point of view? What do you suggest? How do you inject cache in your technologies?
update1: By cache I mean interface, that can query value by key, store it, determine is hit/miss and etc. So it’s some kind of backend storage for https://en.wikipedia.org/wiki/Memoization
4
PSR-6 recommendation regarding Caching Interface expresses a view I personally prefer:
While caching is often an important part of application performance,
it should never be a critical part of application functionality.
So, I’m in favor of considering it as an optional dependency.
No, one either uses a cache or doesn’t.
In your application, one would determine whether caching was necessary. I would inject caching as a decorator pattern.
Consider this interface.
public interface ICommand<in TIn, out TOut>
{
TOut Execute(TIn command);
}
We pass something in and get something back out. Maybe to get something takes a long time. So, we decide to add caching.
public class CacheDecorator<TIn, TOut> : ICommand<TIn, TOut>
{
private readonly ICache _cache;
private readonly ICommand<TIn, TOut> _command;
private readonly string _key;
public CacheDecorator(string key, ICache cache, ICommand<TIn, TOut> command)
{
_command = command;
_key = key;
_cache = cache;
}
public TOut Execute(TIn input)
{
TOut obj;
if (_cache.Get(_key, out obj))
{
Debug.WriteLine(string.Format("Cache hit for key {0}", _key));
return obj;
}
Debug.WriteLine(string.Format("Cache miss for key {0}", _key));
obj = _command.Execute(input);
_cache.Set(_key, obj);
return obj;
}
}
Now any command that get’s something back can be cached. If we don’t need caching then the command is not decorated.
Let’s pretend we are getting a widget and getting a widget is expensive:
public Widget GetWidget(string id)
{
var widgetCommand = new WidgetServiceCommand();
var command = new CacheDecorator<string, Widget>(id, _cache, widgetCommand);
return command.Execute(id);
}
If getting widgets was not expensive, then just remove the decorator and the widget is not cached.
1