Implement a basic CachedWeatherForecaster proxy to cache all results of a WeatherForecaster.

Co-Authored-By: os222
This commit is contained in:
Gleb Koval 2024-11-19 09:10:59 +00:00
parent 68b7b9cf5f
commit 01f8d801b3
Signed by: cyclane
GPG Key ID: 15E168A8B332382C
3 changed files with 105 additions and 0 deletions

View File

@ -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) {}
}

View File

@ -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);
}
}

View File

@ -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);
}
}