Mi piacerebbe avere una soluzione di caching per una varietà di chiamate di funzione.
Tutte le chiamate di funzione corrispondono alla seguente firma
public ResponseType ProcessRequest(RequestType request);
Circa la metà delle volte che la chiave cache può essere applicata in modo molto semplice, in modo generico tirando una chiave dalla stringa serializzata. L'altra metà della volta che la chiave di cache dovrà essere calcolata in modo molto specifico per i dati nella richiesta, utilizzando campi specifici che solo quella richiesta include. Se la risposta dovrebbe essere memorizzata nella cache, quasi sempre sarà certamente fatta in base ai dati dell'oggetto risposta. Ho deciso di disconnettere un intercettatore perché può essere attivato e disattivato ed essere avvolto attorno alla funzione in modo tale che la chiamata alla funzione stessa non abbia la minima idea di ciò che sta accadendo, e questo deve essere applicato a molte chiamate di funzioni diverse dappertutto.
ecco quello che ho finora:
public interface ICacheProvider
{
object GetCachedItem( string cacheKey );
void AddItemToCache( object item, string key );
}
public class CacheProvider
{
private readonly ConcurrentDictionary< string, object > _cacheDictionary;
private CacheProvider() { _cacheDictionary = new ConcurrentDictionary< string, object >(); }
public object GetCachedItem( string cacheKey ) { return _cacheDictionary.ContainsKey( cacheKey ) ? _cacheDictionary[ cacheKey ] : null; }
public void AddItemToCache( object item, string key ) { _cacheDictionary.TryAdd( key, item ); }
}
public interface ICacheKey
{
string GetCacheKey();
}
public interface IIsCacheable
{
bool IsCacheable();
}
public class CacheInterceptor : IInterceptor
{
private readonly ICacheProvider _cacheProvider;
public CacheInterceptor( ICacheProvider cacheProvider ) { _cacheProvider = cacheProvider; }
public void Intercept( IInvocation invocation )
{
var request = invocation.Arguments.First() as ICacheKey;
var requestCacheKey = request.GetCacheKey();
var cachedResponse = _cacheProvider.GetCachedItem( requestCacheKey );
if( cachedResponse != null )
invocation.ReturnValue = cachedResponse;
else
{
invocation.Proceed();
var response = invocation.ReturnValue as IIsCacheable;
if( response.IsCacheable() )
_cacheProvider.AddItemToCache( response, requestCacheKey );
}
}
}
Al momento esiste anche il concetto di un oggetto Transaction che ha un oggetto Request e Response. Ho pensato di applicare il concetto di caching a questo, ma sarebbe akward con un metodo intercettatore perché dovrei recuperare la transazione dal gestore delle transazioni, che è una strana cosa di dipendenza statica per molte altre cose e sto provando per eliminare anche quello.
I problemi con la mia soluzione proposta che vorrei affrontare: - Non penso che questo esempio sia conforme ai principi SOLID, motivo per cui penso a molte altre preoccupazioni. Per favore dimmi perché e come si potrebbe risolvere questo problema?
- dovendo implementare due interfacce separate per la cache di ICacheKey / IIsCacheable sembra un po 'troppo.
- I miei tipi di oggetto richiesta e risposta devono essere a conoscenza della soluzione cache? da un lato questo ha senso perché sanno come sono strutturati i dati. D'altra parte l'idea della memorizzazione nella cache è una preoccupazione separata da come vengono memorizzati i dati e dovrebbe quindi essere in un'altra sezione?