Adapter Pattern_
// "If you want to understand the universe, think in terms of energy, frequency and vibration" - Nikola Tesla
cable What does it consist of?
The Adapter is a structural pattern that allows objects with incompatible interfaces to collaborate.
It functions exactly like a real-world adapter (such as a power plug adapter to use an American plug socket in a European plug). The adapter acts as a wrapper between two objects, catching calls to one object and transforming them to a format and interface recognizable by the second object.
Practical Example: Payment Gateways
Imagine an e-commerce application that uses an internal PaymentProcessor
interface. Over time, we need to integrate a third-party payment gateway like Stripe, but its API
doesn't match our PaymentProcessor
interface.
# The logic behind it
Instead of refactoring our entire application to understand the new Stripe API (which would be invasive
and error-prone), we create an StripeAdapter.
This adapter implements our PaymentProcessor
interface, but under the hood, it translates those calls to the specific methods that the Stripe API
understands. Our application still believes it is talking to a standard PaymentProcessor.
# Structure
# Implementation
<?php
// 1. Target (Interface expected by the client)
interface PaymentProcessor {
public function pay(float $amount): void;
}
// 2. Adaptee (The class we want to adapt, usually third-party)
class StripeAPI {
public function makePayment(float $usdAmount): void {
echo "Processing payment of \${$usdAmount} via Stripe API.\n";
}
}
// 3. Adapter
class StripeAdapter implements PaymentProcessor {
private StripeAPI $stripeAPI;
public function __construct(StripeAPI $stripeAPI) {
$this->stripeAPI = $stripeAPI;
}
public function pay(float $amount): void {
// Here we could perform necessary conversions (e.g., currency matching)
// and delegate the call to the Adaptee
echo "Adapter: Translating request...\n";
$this->stripeAPI->makePayment($amount);
}
}
// 4. Client
class EcommerceApp {
private PaymentProcessor $processor;
public function __construct(PaymentProcessor $processor) {
$this->processor = $processor;
}
public function checkout(float $amount): void {
$this->processor->pay($amount);
}
}
// Usage
$stripeAPI = new StripeAPI();
$adapter = new StripeAdapter($stripeAPI);
$app = new EcommerceApp($adapter);
$app->checkout(150.00);
// Output:
// Adapter: Translating request...
// Processing payment of $150 via Stripe API.
Our application uses the PaymentProcessor
interface. When we want to process a payment, we call the pay
method.
class EcommerceApp {
private PaymentProcessor processor;
public EcommerceApp(PaymentProcessor processor) {
this.processor = processor;
}
public void checkout(double amount) {
processor.pay(amount);
}
}
# Mapping Participants
-
PaymentProcessor (Target): The interface the client expects and understands.
-
StripeAPI (Adaptee): The existing class with the incompatible interface that needs adapting.
-
StripeAdapter (Adapter): The class that implements the
Targetinterface and acts as a bridge, wrapping theAdapteeobject. -
EcommerceApp (Client): The class that collaborates with objects conforming to the
Targetinterface.
# Conclusions
The Adapter pattern excels when we need to use an existing class, but its interface does not match the one we need. It is highly useful in legacy systems or when integrating third-party libraries over which we have no control, adhering seamlessly to the Open/Closed Principle.
# Related Patterns
Bridge
Bridge is usually designed upfront to let abstractions and implementations vary independently. Adapter is usually retrofitted to make incompatible classes work together.
Decorator
Decorator enhances an object without changing its interface, while Adapter changes the interface of an existing object.
Facade
Facade defines a new interface for an entire subsystem, whereas Adapter repurposes an existing interface to make it usable by a specific client.