Adapter Pattern
Note: This post was originally published on AH’s Blog (WordPress) on October 3, 2014, and has been migrated here.
The Adapter pattern is commonly used in applications that expose many functions or operations all serving a specific entity, and you want to make incompatible interfaces work together.
Concept
Think of your computer’s calculator app — it has a Standard mode with basic operations (add, subtract), and a Scientific mode that extends those with advanced operations (multiply, divide). The basic operations have been adapted into the scientific interface.
The Adapter pattern formalizes this: we have two or more different classes, and we want to make them compatible without modifying either.
Scenario
- A basic standard calculator provides
addandsubtract. - We want a unified calculator that also supports
productanddivisionvia the same interface.
Implementation
Define the standard operations interface:
public interface Operations {
public double calculate(double x, double y, char operation);
}
Define the advanced operations interface:
public interface AdvancedOperations {
public double product(double x, double y);
public double divide(double x, double y);
}
Implement the scientific calculator:
public static class Scientific implements AdvancedOperations {
@Override
public double product(double x, double y) { return x * y; }
@Override
public double divide(double x, double y) { return x / y; }
}
Create the adapter — it implements the standard Operations interface but internally delegates to Scientific when needed:
public static class CalculatorAdapter implements Operations {
Scientific scientificMode;
public CalculatorAdapter(String mode) {
if (mode.equals("Scientific")) {
this.scientificMode = new Scientific();
}
}
@Override
public double calculate(double x, double y, char operation) {
if (operation == '*') {
System.out.println("Scientific");
return this.scientificMode.product(x, y);
} else if (operation == '/') {
System.out.println("Scientific");
return this.scientificMode.divide(x, y);
}
if (operation == '+') {
System.out.println("Standard");
return x + y;
} else if (operation == '-') {
System.out.println("Standard");
return x - y;
}
return 0.0;
}
}
The final unified calculator:
public static class Calculator implements Operations {
CalculatorAdapter calculatorAdapter;
@Override
public double calculate(double x, double y, char operation) {
this.calculatorAdapter = new CalculatorAdapter("Scientific");
return this.calculatorAdapter.calculate(x, y, operation);
}
}
Full implementation: GitHub — Design-Patterns/Adapter
References
- GoF, Design Patterns: Elements of Reusable Object-Oriented Software
- Wikipedia: Adapter Pattern
