Adapter - kgleong/software-engineering GitHub Wiki

Motivation

The Adapter design pattern allows translation from one API to another.

This pattern is usually applied when an existing class's interface does not conform to the desired interface.

Code

public interface Target {
    void performOperation();
}

The Target interface specifies the API utilized by clients.

public class Adaptee {
    public void performAdapteeOperation() {
        System.out.println("Adaptee is doing work.");
    }
}

Currently, the Adaptee does not conform to the to the Target interface.

public class Adapter implements Target {
    private Adaptee mAdaptee;

    public Adapter(Adaptee adaptee) {
        mAdaptee = adaptee;
    }

    public void performOperation() {
        // Translate adaptee's API to target API.
        mAdaptee.performAdapteeOperation();
    }
}

As a result, an intermediary Adapter class is used, which does the following:

  • Wraps the non-conforming Adaptee class.
  • Conforms to the Target interface.
  • Performs any translation necessary between the Adaptee and Target APIs.

Use Case

public interface Shape {
    double getArea();
}

The Shape interface defines the desired API that both the Circle and Rectangle classes below need to abide by.

public class Circle implements Shape {
    int mRadius;
    
    public Circle(int radius) {
        mRadius = radius;
    }

    public double getArea() {
        return Math.PI * Math.pow(mRadius, 2);
    }
}

public class Rectangle {
    // Public access to simplify example.
    public int width;
    public int height;

    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }
}

The Circle class already conforms to the Shape API, but the Rectangle class does not.

This may be due to the fact that the Rectangle class is part of an external library, or has some other contractual obligations.

Because of this, the Rectangle class cannot be modified directly, but it still needs to be adapted to conform to the Shape interface.

public class RectangleShapeAdapter implements Shape {
    Rectangle mRectangle;

    public RectangleShapeAdapter(Rectangle rectangle) {
        mRectangle = rectangle;
    }

    public double getArea() {
        return mRectangle.width * mRectangle.height;
    }
}

The RectangleShapeAdapter class solves this translation, by wrapping a Rectangle instance and implmeenting the required getArea() method.

Shape circle = new Circle(5);

Rectangle rectangle = new Rectangle(2, 3);
Shape rectangleShape = new RectangleShapeAdapter(rectangle);

List<Shape> shapeList = new ArrayList<>();
shapeList.add(circle);
shapeList.add(rectangleShape);

for(Shape shape : shapeList) {
    System.out.println("Area is: " + shape.getArea());
}

This allows Rectangle instances to now be treated as any Shape object would be.

References

⚠️ **GitHub.com Fallback** ⚠️