terminal

codeando_simple

terminal

menu

terminal

search_module

guest@codeandosimple: ~/system/search $ grep -r "" .

Press [ENTER] to execute search

Status

Engine: Ready

Database: Online

Index: V2.1.0_LATEST

Software Design / Adapter
guest@codeandosimple: ~/blog/design-patterns $ cat adapter.md

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.

Adapter Example

# 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

Adapter UML Diagram

# Implementation

Adapter.php
<?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.

EcommerceApp.java
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 Target interface and acts as a bridge, wrapping the Adaptee object.

  • EcommerceApp (Client): The class that collaborates with objects conforming to the Target interface.

# 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.