Reputation: 8977
I'm pretty sure there's a better way to do this and I wanted to get some feedback.
I have the following (simplified):
Item
, which implements IItem
Doodad
, which contains a List<IItem>
IItemExistenceVerifier
interface which demands a bool ItemExists(string ItemToCheck)
StandardCachedItemExistenceVerifier
, which includes a FillCache(List<IITem> items)
DoodadValidator
which accepts an IItemExitenceVerifier
and has a Validate
method which calls ItemExists(item)
for each item in the Doodad's list of items.Attempt At a Diagram to express this:
StandardCachedItemExistenceVerifier
and a StandardNonCachedItemVerifier
that I could pass in to the Doodad validatorIn the current structure:
IItemExistenceVerifier
and will not know whether it uses a cache or not. The existence verifier will be newed up in advance and so I can't create a new verifier and pass the items in in the constructor). FillCache()
as part of the validation because it's not required by the interface.Maybe I could:
FillCache()
on even the StandardNonCacheItemVerifier
and have it do nothing? (this seems like a smell)IItemExistenceVerifier
implements some other interface (ICacheDrivenVerifier
) or something and then call FillCache()
if it does?
Upvotes: 2
Views: 522
Reputation: 4643
As usually stated by Steven in his blog, caching is a cross-cutting concern and thus can be solved using decorator. I don't know your final goal, but I assume it is if the cache exists, use cache. If not, get from query and put in cache
.
What you need is to separate the operation into 2 class, one class to retrieve the object, and another to verify.
Here is an example:
public interface IItemRetriever{
public IEnumerable<IItem> GetList();
}
public class StandardItemRetriever : IItemRetriever{
public IEnumerable<IItem> GetList(){
// returning the data
}
}
public class CachedStandardItemRetriever : IItemRetriever{
public CachedStandardItemRetriever(StandardItemRetriever standardItemRetriever){
// property assignment
}
IEnumerable<IItem> items;
public IEnumerable<IItem> GetList(){
if(items == null || !items.Any())
{
items = this.standardItemRetriever.GetList();
}
return items;
}
}
public class StandardItemExistanceVerifier{
public StandardItemExistanceVerifier(IItemRetriever iItemRetriever){
// property assignment
}
}
With this, your verifier will only need to be injected by a IItemRetriever
, in which can be standard or cached.
new StandardItemExistanceVerifier( new CachedStandardItemRetriever(new StandardItemRetriever()) );
new StandardItemExistanceVerifier( new StandardItemRetriever() );
Upvotes: 2
Reputation: 8977
The following is one answer (I think?) and the one I'll go with if I don't see anything better come along:
ICacheFillable<T>
ICacheFillable<string>
FillCacheForVerifier()
method.The FillCacheForVerifier()
method looks like this:
private void FillItemVerifierCache()
{
// Attempt to cast the verifier
var potentiallyCacheableVerifier =
_DoodadValidator.ItemVerifier as ICacheFillable<string>;
// if the item is cacheable
if (potentiallyCacheableVerifier != null)
{
// get all of the items into a list of strings
var cacheItems = from x in _doodad.Items select x.StringProperty;
// fill the cache with the items
potentiallyCacheableVerifier.FillCache(cacheItems);
}
}
So the end result is that it will only fill the cache if the item being passed in fulfills the ICacheFillable interface of its choosing.
If it doesn't strike folks as a good idea (and I'm by no means convinced), then hopefully it will at least help illustrate what I think my problem is.
Upvotes: 0
Reputation: 859
the validator will receive the IItemExistenceVerifier and will not know whether it uses a cache or not.
That's why you have an interface - to hide implementation details. That's fine.
DoodadValidator should not care about caching, as well as IItemExistenceVerifier. It's only StandardCachedItemExistenceVerifier responsibility to work just like any other verifier, but with cache.
How to do it? Method ItemExists should work as follows:
public bool ItemExists( string itemToCheck )
{
// Firstly checking if the item is already in the cache
if( this.cache.ItemExists( itemToCheck ) )
{
return true;
}
// Trying to load the item into the cache. If it doesn't exist, returning false
return this.cache.tryLoadItem( itemToCheck );
}
Upvotes: 0