SeanKilleen
SeanKilleen

Reputation: 8977

C# Class Design: strategy pattern with some classes that have caching functionality?

I'm pretty sure there's a better way to do this and I wanted to get some feedback.

The Components

I have the following (simplified):

Attempt At a Diagram to express this:

A class diagram attempting to illustrate the problem

The Goal

The Question/Problem

In the current structure:

Potential Options

Maybe I could:

Upvotes: 2

Views: 522

Answers (3)

Fendy
Fendy

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

SeanKilleen
SeanKilleen

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:

  • I created an Interface, ICacheFillable<T>
  • I set my verifier to implement ICacheFillable<string>
  • In my processor, right before I loop through all the items to validate them, I call a 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

JustAndrei
JustAndrei

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

Related Questions