Early Access: 87 spots left.

Claim
Low Level DesignAdapterAdapter: Wrap LegacyWeatherSdk in a WeatherProvider

Course content

Adapter: Wrap LegacyWeatherSdk in a WeatherProvider

Medium·Tagsdesign-patternsadapterstructuralrefactoring

Problem Statement

The application uses a `WeatherProvider` interface for forecasting: ```java interface WeatherProvider { double getTemperatureCelsius(String city); String getConditions(String city); // "sunny", "rainy", "cloudy", "snowy" } ``` A new third-party library, `LegacyWeatherSdk`, is the only weather data source you have access to. Its API does not match — it returns Fahrenheit and integer condition codes: ```java class LegacyWeatherSdk { public double readTempF(String location); // returns Fahrenheit public int getCondCode(String location); // 1=sunny, 2=rainy, 3=cloudy, 4=snowy } ``` You cannot change the SDK. The application code (`ForecastService`) is written against `WeatherProvider` and must not import `LegacyWeatherSdk`. Implement `LegacyWeatherAdapter` so that `LegacyWeatherSdk` can be plugged into the application as a `WeatherProvider`. After your refactor, the adapter must satisfy this contract: ```java class LegacyWeatherAdapter implements WeatherProvider { public LegacyWeatherAdapter(LegacyWeatherSdk legacy); // composition: hold the SDK, do not extend it public double getTemperatureCelsius(String city); // (F - 32) * 5 / 9 public String getConditions(String city); // 1→"sunny", 2→"rainy", 3→"cloudy", 4→"snowy", else "unknown" } ``` The validator runs three checks: 1. *translates_temperature_and_conditions* — given a `LegacyWeatherSdk` returning known Fahrenheit values (32°F, 50°F, 212°F) and codes 1-4, the adapter must return the corresponding Celsius (0°C, 10°C, 100°C) and condition strings ("sunny", "rainy", "cloudy", "snowy"). 2. *unknown_code_falls_back* — for an unrecognised code (e.g. 99), `getConditions(...)` must return `"unknown"`. Throwing or returning `null` is not acceptable; the adapter is the place where unknown legacy codes get handled. 3. *composition_and_end_to_end* — the adapter implements `WeatherProvider`; its constructor accepts a `LegacyWeatherSdk`; it does NOT extend `LegacyWeatherSdk` (composition over inheritance). A `ForecastService` wired with the adapter produces the expected forecast string end-to-end. The stub adapter throws `UnsupportedOperationException` from every method, so it fails every check until the methods are implemented.

Examples

Example 1
Input
var sdk = stub returning 50.0°F and code 1; new LegacyWeatherAdapter(sdk).getTemperatureCelsius("Paris")
Output
"10.0"
Why
(50 - 32) * 5/9 = 10. The conversion lives in the adapter; the application sees only Celsius.
Example 2
Input
var sdk = stub returning code 3; new LegacyWeatherAdapter(sdk).getConditions("London")
Output
"\"cloudy\""
Why
Code 3 maps to "cloudy". The mapping is the adapter's job; the application speaks only in named conditions.
Example 3
Input
var sdk = stub returning code 99; new LegacyWeatherAdapter(sdk).getConditions("Mars")
Output
"\"unknown\""
Why
Unknown legacy codes get a sensible fallback so the application never sees a raw integer or a null.

Constraints

  • LegacyWeatherAdapter must implement the WeatherProvider interface.
  • LegacyWeatherAdapter must accept a LegacyWeatherSdk in its constructor and hold it as a private field (composition, not inheritance).
  • LegacyWeatherAdapter must NOT extend LegacyWeatherSdk.
  • getTemperatureCelsius converts Fahrenheit using (F - 32) * 5 / 9.
  • getConditions maps 1→"sunny", 2→"rainy", 3→"cloudy", 4→"snowy"; any other code returns "unknown".
  • The adapter must not throw for unknown condition codes.

Hints

Stuck? Reveal a nudge toward the right pattern, one step at a time.

Hint 1
Add a private final LegacyWeatherSdk field to LegacyWeatherAdapter, and assign it from the constructor parameter. Composition, not inheritance — do NOT make the adapter extend LegacyWeatherSdk.
Hint 2
getTemperatureCelsius is one line: read Fahrenheit from the field's readTempF(city), apply (f - 32) * 5 / 9, return.
Hint 3
getConditions is a switch on legacy.getCondCode(city). Cover 1 → "sunny", 2 → "rainy", 3 → "cloudy", 4 → "snowy", default → "unknown". Do not throw for unknown codes.
Hint 4
The conversion math and the code-to-string mapping live ONLY inside the adapter. ForecastService should never see Fahrenheit or integer codes; the whole point of the adapter is to keep that translation in one place.