Implement cache size limitation and eviction for CachedWeatherForecaster.
Co-Authored-By: os222
This commit is contained in:
parent
01f8d801b3
commit
30cd615adb
|
@ -1,14 +1,19 @@
|
|||
package ic.doc;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Queue;
|
||||
|
||||
// This class is a decorator for WeatherForecaster that caches all results.
|
||||
public class CachedWeatherForecaster implements WeatherForecaster {
|
||||
private final WeatherForecaster forecaster;
|
||||
private final Integer maxCacheSize;
|
||||
private final HashMap<CacheKey, WeatherForecast> cache = new HashMap<>();
|
||||
private final Queue<CacheKey> evictionQueue = new ArrayDeque<>();
|
||||
|
||||
CachedWeatherForecaster(WeatherForecaster forecaster) {
|
||||
CachedWeatherForecaster(WeatherForecaster forecaster, Integer maxCacheSize) {
|
||||
this.forecaster = forecaster;
|
||||
this.maxCacheSize = maxCacheSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -17,11 +22,19 @@ public class CachedWeatherForecaster implements WeatherForecaster {
|
|||
WeatherForecast forecast = cache.get(key);
|
||||
if (forecast == null) {
|
||||
forecast = forecaster.forecastFor(region, day);
|
||||
cache.put(key, forecast);
|
||||
putCache(key, forecast);
|
||||
return forecast;
|
||||
}
|
||||
return forecast;
|
||||
}
|
||||
|
||||
private void putCache(CacheKey key, WeatherForecast forecast) {
|
||||
if (maxCacheSize != null && cache.size() >= maxCacheSize) {
|
||||
cache.remove(evictionQueue.poll());
|
||||
}
|
||||
cache.put(key, forecast);
|
||||
evictionQueue.add(key);
|
||||
}
|
||||
|
||||
private record CacheKey(WeatherRegion region, Weekday day) {}
|
||||
}
|
|
@ -2,6 +2,7 @@ package ic.doc;
|
|||
|
||||
public class CachedWeatherForecasterBuilder {
|
||||
private WeatherForecaster forecaster;
|
||||
private Integer maxCacheSize = null;
|
||||
|
||||
private CachedWeatherForecasterBuilder() {}
|
||||
|
||||
|
@ -14,7 +15,12 @@ public class CachedWeatherForecasterBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public CachedWeatherForecasterBuilder withMaxCacheSize(int maxCacheSize) {
|
||||
this.maxCacheSize = maxCacheSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CachedWeatherForecaster build() {
|
||||
return new CachedWeatherForecaster(forecaster);
|
||||
return new CachedWeatherForecaster(forecaster, maxCacheSize);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,4 +55,34 @@ public class CachedWeatherForecasterTest {
|
|||
cachedForecaster.forecastFor(WeatherRegion.LONDON, Weekday.MONDAY);
|
||||
assertEquals(expForecast, actForecast);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forecastForCacheEvictedCall() {
|
||||
WeatherForecaster cachedForecaster = cachedWeatherForecaster.withMaxCacheSize(2).build();
|
||||
WeatherForecast expForecast = new WeatherForecast("Sunny Spells", 30);
|
||||
WeatherForecast badForecast = new WeatherForecast("Rainy", 10);
|
||||
context.checking(new Expectations() {{
|
||||
// Two calls since cache gets evicted
|
||||
exactly(2).of(forecaster).forecastFor(WeatherRegion.LONDON, Weekday.MONDAY);
|
||||
will(returnValue(expForecast));
|
||||
// Also make some other requests in-between
|
||||
oneOf(forecaster).forecastFor(WeatherRegion.LONDON, Weekday.TUESDAY);
|
||||
will(returnValue(badForecast));
|
||||
oneOf(forecaster).forecastFor(WeatherRegion.WALES, Weekday.MONDAY);
|
||||
will(returnValue(badForecast));
|
||||
}});
|
||||
// Cache put
|
||||
cachedForecaster.forecastFor(WeatherRegion.LONDON, Weekday.MONDAY);
|
||||
// Cache put
|
||||
cachedForecaster.forecastFor(WeatherRegion.LONDON, Weekday.TUESDAY);
|
||||
// Size exceeded, (London, Monday) entry evicted
|
||||
cachedForecaster.forecastFor(WeatherRegion.WALES, Weekday.MONDAY);
|
||||
// Size exceeded, (London, Tuesday) entry evicted
|
||||
WeatherForecast actForecast =
|
||||
cachedForecaster.forecastFor(WeatherRegion.LONDON, Weekday.MONDAY);
|
||||
assertEquals(expForecast, actForecast);
|
||||
// Caching still works (3rd call not made)
|
||||
actForecast = cachedForecaster.forecastFor(WeatherRegion.LONDON, Weekday.MONDAY);
|
||||
assertEquals(expForecast, actForecast);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue