Java > Design Patterns in Java > Structural Patterns > Adapter Pattern
Adapter Pattern Example: Converting Celsius to Fahrenheit
The Adapter pattern allows incompatible interfaces to work together. This example demonstrates adapting a Celsius temperature sensor to a system that expects Fahrenheit.
Concepts Behind the Snippet
The Adapter pattern essentially wraps an existing class with a new interface that the client expects. This involves creating an 'adapter' class that implements the target interface and internally uses the adaptee (the class being adapted). It promotes reusability and flexibility by allowing existing, potentially legacy, code to be integrated into new systems without modification.
Celsius Temperature Sensor (Adaptee)
This is the class we want to adapt. It provides temperature readings in Celsius, but our client needs Fahrenheit.
public class CelsiusTemperatureSensor {
public double getCelsiusTemperature() {
// Simulate reading temperature from a sensor
return Math.random() * 40; // Temperature between 0 and 40 Celsius
}
}
Fahrenheit Temperature Interface (Target)
This interface represents the temperature system our client expects. It defines a method to retrieve the temperature in Fahrenheit.
public interface FahrenheitTemperature {
double getFahrenheitTemperature();
}
Temperature Adapter (Adapter)
This is the adapter class. It implements the `FahrenheitTemperature` interface, but internally uses a `CelsiusTemperatureSensor` to get the temperature in Celsius and then converts it to Fahrenheit.
public class TemperatureAdapter implements FahrenheitTemperature {
private CelsiusTemperatureSensor celsiusSensor;
public TemperatureAdapter(CelsiusTemperatureSensor celsiusSensor) {
this.celsiusSensor = celsiusSensor;
}
@Override
public double getFahrenheitTemperature() {
double celsius = celsiusSensor.getCelsiusTemperature();
return celsiusToFahrenheit(celsius);
}
private double celsiusToFahrenheit(double celsius) {
return (celsius * 9 / 5) + 32;
}
}
Client Code
This is the client code that uses the `FahrenheitTemperature` interface. It doesn't need to know anything about the `CelsiusTemperatureSensor` or the conversion process.
public class Client {
public static void main(String[] args) {
CelsiusTemperatureSensor celsiusSensor = new CelsiusTemperatureSensor();
FahrenheitTemperature adapter = new TemperatureAdapter(celsiusSensor);
double fahrenheit = adapter.getFahrenheitTemperature();
System.out.println("Temperature in Fahrenheit: " + fahrenheit);
}
}
Real-Life Use Case
Consider integrating a legacy payment processing system (which only supports one currency) with a modern e-commerce platform that supports multiple currencies. You can use an adapter to convert the e-commerce platform's currency requests into the currency supported by the legacy system, allowing the two systems to work together seamlessly.
Best Practices
Interview Tip
Be prepared to explain the difference between the Adapter and Decorator patterns. While both can wrap an existing object, the Adapter changes the interface of the object, while the Decorator adds responsibilities without changing the interface.
When to use them
Use the Adapter pattern when:
Memory Footprint
The adapter pattern adds a small memory footprint due to the adapter object itself. The memory used is primarily determined by the fields held by the adapter (e.g., the reference to the adaptee) and the code within the adapter methods. The impact is generally negligible compared to the overall application size.
Alternatives
Alternatives to the adapter pattern include:
Pros
Cons
FAQ
-
What is the key benefit of using the Adapter pattern?
The key benefit is enabling collaboration between classes with incompatible interfaces without modifying their existing code. -
When should I *not* use the Adapter pattern?
If the interfaces are only slightly different, and you have control over the adaptee's code, refactoring the adaptee might be a simpler solution.