Реализация центрального класса "менеджер" для экземпляров определенного типа в нескольких сборках
В нашем программном обеспечении мы иногда используем определенный класс для кэширования комбинаций ключей и значений, чтобы предотвратить повторный поиск одних и тех же значений из базы данных. Поскольку число реализаций кэша увеличивается, я хотел бы централизовать управление всеми реализациями кэша и обобщить реализацию различных классов кэша.
Поэтому я создал общий класс 'Cache', который является частным вложенным классом статического класса CacheManager. Из-за закрытого вложенного класса Cache этот класс не может быть инициирован никаким другим классом, кроме самого CacheManager.
Причина, по которой я хочу использовать диспетчер кэша, заключается в том, что я хочу иметь возможность сбрасывать все кэши и получать статистику для всех кэшей без пропусков реализаций кэша, о которых я не знаю (созданных коллегами).
Интерфейс ICache используется для предоставления кэшей коду вне класса CacheManager.
Упрощенные реализации:
Интерфейс
// Interface for all available caches
public interface ICache<TKey, TValue>
{
bool StatisticsEnabled { get; set; }
KeyStatistics[] Statistics { get; }
// Set cache item (including update)
void Set(TKey key, TValue item);
// Get an item from the cache (return value indicates found / not found in cache)
bool Get(TKey key, out TValue value);
}
Объекты данных для статистики
// Statistics per key in the cache (or requested from the cache)
public class KeyStatistics
{
public string Name { get; set; }
public int RequestCount { get; set; }
public int HitCount { get; set; }
}
// Contains statistics per cache
public class CacheStatistics
{
public string Name { get; set; }
public KeyStatistics[] Statistics { get; set; }
}
Статический менеджер кеша, включая реализацию общего кеша
public static class CacheManager
{
private static Lazy<Cache<string, string>> _settingsCache = new Lazy<Cache<string, string>>();
private static Lazy<Cache<DateTime, short>> _mechanicCountCache = new Lazy<Cache<DateTime, short>>();
// actual supported caches
public static ICache<string, string> SettingsCache { get { return _settingsCache.Value; } }
public static ICache<DateTime, short> MechanicCountCache { get { return _mechanicCountCache.Value; } }
public static IEnumerable<CacheStatistics> Statistics
{
get
{
yield return new CacheStatistics
{
Name = "Settings cache",
Statistics = _settingsCache.Value.Statistics
};
yield return new CacheStatistics
{
Name = "Mechanics count cache",
Statistics = _mechanicCountCache.Value.Statistics
};
}
}
// Private class, so it cannot be initiated by anything else than the cache manager
private class Cache<TKey, TValue> : ICache<TKey, TValue>
{
private ConcurrentDictionary<TKey, KeyStatistics> _statistics = new ConcurrentDictionary<TKey, KeyStatistics>();
private ConcurrentDictionary<TKey, TValue> _cachedValues = new ConcurrentDictionary<TKey, TValue>();
// Constructor
public Cache()
{
// Do some constructing things
}
#region ICache
public bool StatisticsEnabled { get; set; }
public KeyStatistics[] Statistics
{
get { return _statistics.Values.ToArray(); }
}
public void Set(TKey key, TValue item)
{
// Todo: add to cache or update existing value
}
public bool Get(TKey key, out TValue item)
{
// Todo: fetch from dictionary
// Todo: update statistics
item = default(TValue);
return false;
}
#endregion ICache
}
Это будет работать как требуется. Однако есть кое-что, что я еще не понял. Мы работаем с несколькими сборками (базовыми сборками и "специализированными" сборками). Специализированные сборки имеют ссылку на основные сборки, но не наоборот.
Я хочу, чтобы CacheManager (часть сборки ядра) мог управлять кэшем с типом TValue из специализированной сборки. Я хочу, чтобы кэш был виден только из специализированной сборки. Я знаю, что не могу использовать частичные классы, и я не думаю, что расширения также помогут мне.
Есть ли способ добиться того, чего я хочу?
2 ответа
Я закончил с кеш-менеджером в основной сборке. Этот менеджер кэша не знает о специализированных типах кэша в ссылочных сборках. Вместо этого у него есть метод GetCache(), который вызывается с использованием универсального типа. Универсальный тип должен быть реализацией ICache.
В реализации GetCache менеджер кэша использует универсальный класс Singleton, который может создавать одноэлементный экземпляр типа (в данном случае тип, реализующий ICache).
Перевод: * GetStatistieken() > GetStatistics() * Wissen() > Очистить все кэшированное содержимое
В ссылочных сборках экземпляр кэша может быть выбран следующим образом:
var cache = CacheManager.GetCache<DagCapaciteitCache>();
Для простоты создания нового кэша экземпляры кэша могут быть подклассами одного из двух базовых классов кэша, но это не обязательно. Единственное требование состоит в том, чтобы кеш реализовывал интерфейс IQuery (определенный в базовой сборке).
Немного поздно для OP. Для других реализация фабричного паттерна может быть выходом. Затем отражение используется для реализации всех типов на заводе и повторяется для сброса всех / определенных кешей.
например https://www.dofactory.com/net/factory-method-design-pattern
Надеюсь это поможет.
Вы можете хранить только сериализованные значения объектов в самом менеджере кэша. Ссылочные сборки должны иметь соответствующие специализированные ссылки на сборки.
В прошлом Json.NET хорошо работал для сериализации / десериализации универсальных объектов.