Card 03/ 08

CodeDifficulty: Intermediate2 min

Adapter Template in Python, Java and TypeScript

One Target interface, one Adaptee with the wrong method, and an Adapter that translates the call.

The Adapter template is the pattern in its pure form, with the participant names from the class diagram. The adaptee returns its text reversed, so the adapter has a real translation to make rather than a rename. The steps add each participant in Python, and the tabs give the complete program in three languages, each with its output.

Building the template one participant at a time

Target

The interface the client already expects.

py
class Target(ABC):
    @abstractmethod
    def request(self) -> str: ...

Adaptee

An existing class with useful behaviour under another name and in another form.

py
class Adaptee:
    def specific_request(self) -> str:
        return ".eetpadA eht fo ruoivaheb lufesU"

Adapter

Implements the target, holds the adaptee, and translates each call.

py
class Adapter(Target):
    def __init__(self, adaptee: Adaptee) -> None:
        self._adaptee = adaptee

    def request(self) -> str:
        return self._adaptee.specific_request()[::-1]

Client

Written against the target alone, it is given the adapter.

py
def client(target: Target) -> None:
    print(target.request())


client(Adapter(Adaptee()))

The complete template

py
from abc import ABC, abstractmethod


class Target(ABC):
    @abstractmethod
    def request(self) -> str: ...


class Adaptee:
    def specific_request(self) -> str:
        return ".eetpadA eht fo ruoivaheb lufesU"


class Adapter(Target):
    def __init__(self, adaptee: Adaptee) -> None:
        self._adaptee = adaptee

    def request(self) -> str:
        return self._adaptee.specific_request()[::-1]


def client(target: Target) -> None:
    print(target.request())


client(Adapter(Adaptee()))
OutputRan with python:3.12-slim (Python 3.12.13)
Useful behaviour of the Adaptee.
The adapter holds the adaptee and reverses its answer into the form the client expects.
java
public class AdTemplate {
    static void client(Target target) {
        System.out.println(target.request());
    }

    public static void main(String[] args) {
        client(new Adapter(new Adaptee()));
    }
}

interface Target {
    String request();
}

class Adaptee {
    String specificRequest() {
        return ".eetpadA eht fo ruoivaheb lufesU";
    }
}

class Adapter implements Target {
    private final Adaptee adaptee;

    Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    public String request() {
        return new StringBuilder(adaptee.specificRequest()).reverse().toString();
    }
}
OutputRan with eclipse-temurin:21-jdk (Java 21.0.12)
Useful behaviour of the Adaptee.
Java places the client first so the source launcher finds `main`; the roles are the same.
ts
interface Target {
  request(): string;
}

class Adaptee {
  specificRequest(): string {
    return ".eetpadA eht fo ruoivaheb lufesU";
  }
}

class Adapter implements Target {
  constructor(private readonly adaptee: Adaptee) {}

  request(): string {
    return this.adaptee.specificRequest().split("").reverse().join("");
  }
}

function client(target: Target): void {
  console.log(target.request());
}

client(new Adapter(new Adaptee()));
OutputRan with node:22-slim (Node 22.23.1), TypeScript 5.9.3
Useful behaviour of the Adaptee.
A parameter property stores the adaptee in one line; the translation is the same.

In all three the client calls request() and prints a readable sentence, never learning that the text came from specific_request() backwards. The adaptee is untouched: nothing in it knows the target exists, so the pattern works even when the adaptee is a library you cannot edit.