Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Bridging Diverse Systems with the Adapter Pattern

Tech 2

The Adapter pattern serves as a bridge between incompatible interfaces, enabling seamless integration of existing componants into new systems without altering their original structure. This is particular useful in scenarios where third-party services—such as Alipay or WeChat Pay—must be incorporated into an e-commerce platform that already has its own payment interface.

Core Concept

The Adapter pattern introduces a wrapper class (the adapter) that translates one interface into another expected by the client. This allows disparate systems to work together harmoniously. There are two primary forms:

  • Object Adapter: Uses composition—where the adapter holds a reference to the adaptee.
  • Class Adapter: Uses inheritance—where the adapter extends the adaptee and implements the target interface.

Structural Components

  • Target Interface: The interface the client expects to use.
  • Adaptee Class: The existing class with methods that need to be accessed.
  • Adapter Class: The bridge that transforms calls from the Target enterface into calls on the Adaptee.

Implementation Examples

Object Adapter

interface PaymentGateway {
    void processPayment();
}

class AlipayService {
    public void makePayment() {
        System.out.println("Processing payment via Alipay");
    }
}

class AlipayAdapter implements PaymentGateway {
    private final AlipayService alipay;

    public AlipayAdapter(AlipayService alipay) {
        this.alipay = alipay;
    }

    @Override
    public void processPayment() {
        alipay.makePayment();
    }
}

Class Adapter

interface PaymentGateway {
    void processPayment();
}

class AlipayService {
    public void makePayment() {
        System.out.println("Processing payment via Alipay");
    }
}

class AlipayAdapter extends AlipayService implements PaymentGateway {
    @Override
    public void processPayment() {
        makePayment();
    }
}

Client Usage

public class PaymentClient {
    public static void main(String[] args) {
        AlipayService alipay = new AlipayService();
        PaymentGateway gateway = new AlipayAdapter(alipay);
        gateway.processPayment(); // Output: Processing payment via Alipay
    }
}

Advantages and Limitations

Pros:

  • Decouples clients from specific implementations.
  • Promotes code reuse by wrapping legacy classes.
  • Separates adaptation logic from business logic.

Cons:

  • Class adapter limited to single inheritance in Java.
  • Adds complexity through additional classes and interfaces.

Applicable Scenarios

  • Integrating external libraries with non-matching APIs.
  • Reusing existing classes within a system that requires different method signatures.

Advanced Variants

Bidirectional Adapter

Enables mutual communication between two incompatible interfaces by holding references to both.

interface ServiceEndpoint {
    void sendToClient(String message);
}

interface ClientEndpoint {
    void sendToService(String message);
}

class ServiceImpl implements ServiceEndpoint {
    @Override
    public void sendToClient(String msg) {
        System.out.println("Service received: " + msg);
    }
}

class ClientImpl implements ClientEndpoint {
    @Override
    public void sendToService(String msg) {
        System.out.println("Client received: " + msg);
    }
}

class BiDirectionalAdapter implements ServiceEndpoint, ClientEndpoint {
    private final ServiceImpl service;
    private final ClientImpl client;

    public BiDirectionalAdapter(ServiceImpl service, ClientImpl client) {
        this.service = service;
        this.client = client;
    }

    @Override
    public void sendToClient(String msg) {
        client.sendToService(msg);
    }

    @Override
    public void sendToService(String msg) {
        service.sendToClient(msg);
    }
}

Default Adapter Pattern

Reduces boilerplate when implementing large interfaces. It provides default empty implementations, so subclasses only override needed methods.

interface ViewRenderer {
    void renderBanner();
    void renderColor();
    void renderButton();
    void renderCommand();
    void renderStyles();
    void renderShape();
}

abstract class BaseViewAdapter implements ViewRenderer {
    public void renderBanner() {}
    public void renderColor() {}
    public void renderButton() {}
    public void renderCommand() {}
    public void renderStyles() {}
    public void renderShape() {}
}

class CustomLinuxView extends BaseViewAdapter {
    @Override
    public void renderCommand() {
        System.out.println("Displaying command prompt");
    }
}

This pattern simplifies development when full interface implementation is unnecessary.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.