Structural Pattern
Adapter Pattern
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that could not otherwise because of incompatible interfaces.
10 min readHigh Priority
1What is Adapter Pattern?
Real-World Analogy
Power Plug Adapter
You have a US laptop charger but are in Europe. You use a plug adapter to convert the US plug interface to European socket interface. The charger works unchanged.
Card Reader
Your laptop has USB ports, but your camera uses SD cards. A card reader adapts the SD card interface to USB, letting them work together.
Adapter (also known as Wrapper) is a structural pattern that allows objects with incompatible interfaces to collaborate. It wraps an object and exposes a different interface that the client expects.
Adapter Pattern Structure
Adapter implements Target interface and wraps Adaptee, translating calls.
2Object Adapter vs Class Adapter
Object Adapter (Composition)
Adapter holds reference to adaptee. More flexible.
class Adapter implements Target {
private Adaptee adaptee;
Adapter(Adaptee a) {
this.adaptee = a;
}
request() {
adaptee.specificRequest();
}
}- + Can adapt multiple adaptees
- + Works with subclasses
Class Adapter (Inheritance)
Adapter extends adaptee. Requires multiple inheritance.
// Requires multiple inheritance
class Adapter extends Adaptee
implements Target {
request() {
this.specificRequest();
}
}- - Needs multiple inheritance
- + Can override adaptee behavior
Which to Use?
Object Adapter is preferred in most languages (Java, Python, C#) since they don't support multiple inheritance. Use Class Adapter only in C++ when you need to override adaptee methods.
3Implementation
Adapter Pattern - Payment Gateway Integration
// ========== Target Interface (what our system expects) ==========
interface PaymentProcessor {
void pay(String orderId, double amount);
boolean refund(String transactionId);
}
// ========== Adaptee (third-party payment gateway with different interface) ==========
class StripeGateway {
public String createCharge(double amountInCents, String currency, String description) {
System.out.println("Stripe: Charging " + amountInCents + " cents");
return "ch_" + System.currentTimeMillis();
}
public boolean reverseCharge(String chargeId) {
System.out.println("Stripe: Reversing charge " + chargeId);
return true;
}
}
// ========== Adapter ==========
class StripeAdapter implements PaymentProcessor {
private StripeGateway stripe;
public StripeAdapter(StripeGateway stripe) {
this.stripe = stripe;
}
@Override
public void pay(String orderId, double amount) {
// Convert dollars to cents, adapt interface
long amountInCents = Math.round(amount * 100);
String description = "Order: " + orderId;
stripe.createCharge(amountInCents, "USD", description);
}
@Override
public boolean refund(String transactionId) {
// Adapt method name
return stripe.reverseCharge(transactionId);
}
}
// ========== Another Adaptee ==========
class PayPalSDK {
public void sendPayment(String recipient, double amount) {
System.out.println("PayPal: Sending $" + amount);
}
public void cancelPayment(String paymentId) {
System.out.println("PayPal: Cancelling " + paymentId);
}
}
// ========== Another Adapter ==========
class PayPalAdapter implements PaymentProcessor {
private PayPalSDK paypal;
public PayPalAdapter(PayPalSDK paypal) {
this.paypal = paypal;
}
@Override
public void pay(String orderId, double amount) {
paypal.sendPayment("merchant@store.com", amount);
}
@Override
public boolean refund(String transactionId) {
paypal.cancelPayment(transactionId);
return true;
}
}
// ========== Client Code ==========
public class Main {
public static void main(String[] args) {
// Client code works with any PaymentProcessor
PaymentProcessor processor;
// Use Stripe
processor = new StripeAdapter(new StripeGateway());
processor.pay("ORDER-123", 99.99);
// Switch to PayPal - same interface!
processor = new PayPalAdapter(new PayPalSDK());
processor.pay("ORDER-456", 49.99);
}
}Output:
Stripe: Charging 9999 cents PayPal: Sending $49.99
4Real-World Applications
JDBC Drivers
Oracle, MySQL, PostgreSQL drivers
Each database driver adapts vendor-specific API to standard JDBC interface.
Logging Facades
SLF4J adapting Log4j, Logback
SLF4J provides a common interface, adapters connect to various logging implementations.
Legacy Integration
Wrapping old APIs
Adapt legacy system interfaces to modern API contracts without modifying old code.
Third-Party Libraries
Payment, SMS, Email gateways
Create adapters for each vendor so your code uses a unified interface.
5Interview Follow-up Questions
Interview Follow-up Questions
Common follow-up questions interviewers ask
6Key Takeaways
1Adapter converts one interface to another.
2Enables incompatible classes to work together.
3Object Adapter (composition) is preferred over Class Adapter.
4Different from Decorator (adds behavior) and Facade (simplifies).
5Used for: third-party integration, legacy migration, vendor abstraction.
6Examples: JDBC drivers, payment gateways, logging facades.