Implement a basic CachedWeatherForecaster proxy to cache all results of a WeatherForecaster.
Co-Authored-By: os222
This commit is contained in:
parent
68b7b9cf5f
commit
01f8d801b3
|
@ -0,0 +1,27 @@
|
||||||
|
package ic.doc;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
// This class is a decorator for WeatherForecaster that caches all results.
|
||||||
|
public class CachedWeatherForecaster implements WeatherForecaster {
|
||||||
|
private final WeatherForecaster forecaster;
|
||||||
|
private final HashMap<CacheKey, WeatherForecast> cache = new HashMap<>();
|
||||||
|
|
||||||
|
CachedWeatherForecaster(WeatherForecaster forecaster) {
|
||||||
|
this.forecaster = forecaster;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WeatherForecast forecastFor(WeatherRegion region, Weekday day) {
|
||||||
|
CacheKey key = new CacheKey(region, day);
|
||||||
|
WeatherForecast forecast = cache.get(key);
|
||||||
|
if (forecast == null) {
|
||||||
|
forecast = forecaster.forecastFor(region, day);
|
||||||
|
cache.put(key, forecast);
|
||||||
|
return forecast;
|
||||||
|
}
|
||||||
|
return forecast;
|
||||||
|
}
|
||||||
|
|
||||||
|
private record CacheKey(WeatherRegion region, Weekday day) {}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package ic.doc;
|
||||||
|
|
||||||
|
public class CachedWeatherForecasterBuilder {
|
||||||
|
private WeatherForecaster forecaster;
|
||||||
|
|
||||||
|
private CachedWeatherForecasterBuilder() {}
|
||||||
|
|
||||||
|
public static CachedWeatherForecasterBuilder cachedWeatherForecaster() {
|
||||||
|
return new CachedWeatherForecasterBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CachedWeatherForecasterBuilder withForecaster(WeatherForecaster forecaster) {
|
||||||
|
this.forecaster = forecaster;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CachedWeatherForecaster build() {
|
||||||
|
return new CachedWeatherForecaster(forecaster);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package ic.doc;
|
||||||
|
|
||||||
|
import org.jmock.Expectations;
|
||||||
|
import org.jmock.integration.junit4.JUnitRuleMockery;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static ic.doc.CachedWeatherForecasterBuilder.cachedWeatherForecaster;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
// Unit test for CachedWeatherForecaster decorator
|
||||||
|
public class CachedWeatherForecasterTest {
|
||||||
|
@Rule
|
||||||
|
public JUnitRuleMockery context = new JUnitRuleMockery();
|
||||||
|
|
||||||
|
private final WeatherForecaster forecaster = context.mock(WeatherForecaster.class);
|
||||||
|
private final CachedWeatherForecasterBuilder cachedWeatherForecaster =
|
||||||
|
cachedWeatherForecaster().withForecaster(forecaster);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void forecastForInitialCall() {
|
||||||
|
WeatherForecaster cachedForecaster = cachedWeatherForecaster.build();
|
||||||
|
WeatherForecast expForecast = new WeatherForecast("Sunny", 20);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(forecaster).forecastFor(WeatherRegion.LONDON, Weekday.MONDAY);
|
||||||
|
will(returnValue(expForecast));
|
||||||
|
}});
|
||||||
|
WeatherForecast actForecast = cachedForecaster.forecastFor(
|
||||||
|
WeatherRegion.LONDON, Weekday.MONDAY
|
||||||
|
);
|
||||||
|
assertEquals(expForecast, actForecast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void forecastForCachedCall() {
|
||||||
|
WeatherForecaster cachedForecaster = cachedWeatherForecaster.build();
|
||||||
|
WeatherForecast expForecast = new WeatherForecast("Sunny Spells", 30);
|
||||||
|
WeatherForecast badForecast = new WeatherForecast("Rainy", 10);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Only one call, second must hit cache
|
||||||
|
oneOf(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));
|
||||||
|
}});
|
||||||
|
cachedForecaster.forecastFor(WeatherRegion.LONDON, Weekday.MONDAY);
|
||||||
|
cachedForecaster.forecastFor(WeatherRegion.LONDON, Weekday.TUESDAY);
|
||||||
|
cachedForecaster.forecastFor(WeatherRegion.WALES, Weekday.MONDAY);
|
||||||
|
WeatherForecast actForecast =
|
||||||
|
cachedForecaster.forecastFor(WeatherRegion.LONDON, Weekday.MONDAY);
|
||||||
|
assertEquals(expForecast, actForecast);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue