2.1 Adapter Pattern - Structural Design Pattern

The Adapter pattern is a useful tool in software development that can be used to integrate interfaces that are incompatible. It enables seamless collaboration between objects with different interfaces. The Adapter pattern is unique among design patterns in that it may effectively bridge the gap between disparate interfaces, facilitating harmonic component interaction. We'll explore the Adapter pattern, its Java implementation, and its practical applications in this blog.

Understanding the Adapter Pattern

Two incompatible interfaces can communicate with each other without requiring changes to their existing code thanks to the Adapter pattern, which serves as a translator between them. It does this by offering a wrapper that changes a class's interface into a different interface that the client expects. This makes it possible for components that would not otherwise work together, which encourages code reuse and flexibility.

Implementation in Java

Let's illustrate the Adapter pattern with a simple example in Java. Consider a scenario where we have an existing LegacyRectangle class representing rectangles with methods draw() and resize(). However, a new client code expects rectangles to have methods display() and changeSize(). We can use the Adapter pattern to bridge this gap.

// Adaptee: Existing class with incompatible interface
class LegacyRectangle {
    void draw() {
        System.out.println("LegacyRectangle: Drawing a rectangle.");
    }
    void resize() {
        System.out.println("LegacyRectangle: Resizing the rectangle.");
    }
}
// Target: Expected interface by the client
interface Rectangle {
    void display();
    void changeSize();
}
// Adapter: Adapts the LegacyRectangle to the Rectangle interface
class RectangleAdapter implements Rectangle {
    private final LegacyRectangle legacyRectangle;
    RectangleAdapter(LegacyRectangle legacyRectangle) {
        this.legacyRectangle = legacyRectangle;
    }
    @Override
    public void display() {
        legacyRectangle.draw();
    }
    @Override
    public void changeSize() {
        legacyRectangle.resize();
    }
}
// Client code
public class Client {
    public static void main(String[] args) {
        // Using the Adapter to interact with the LegacyRectangle
        LegacyRectangle legacyRectangle = new LegacyRectangle();
        Rectangle adapter = new RectangleAdapter(legacyRectangle);
        // Client code interacts with the Rectangle interface
        adapter.display();
        adapter.changeSize();
    }
}

In this example:

  • LegacyRectangle represents the existing class with an incompatible interface.

  • Rectangle is the target interface expected by the client.

  • RectangleAdapter acts as the adapter, translating method calls from the Rectangle interface to the methods of LegacyRectangle.

  • The client code interacts with the Rectangle interface, unaware of the underlying implementation details.

Benefits of the Adapter Pattern

  • Compatibility: Enables integration between components with incompatible interfaces.

  • Flexibility: Promotes code reuse and flexibility by allowing interaction between diverse components.

  • Maintainability: Encourages separation of concerns and minimizes code modification, enhancing maintainability.

Conclusion :

One effective technique for merging separate components with incompatible interfaces is the Adapter pattern. It creates a bridge across disparate interfaces, allowing for smooth communication and encouraging code reuse. The Adapter pattern is easy to implement in Java and provides a workable fix for interface compatibility problems. The Adapter design can improve the flexibility of your software components and make interoperability easier, regardless of whether you're working with old code or connecting with external libraries.

5
Subscribe to my newsletter

Read articles from Venu Madhav Emmadi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Venu Madhav Emmadi
Venu Madhav Emmadi