Skip to content

Adapter pattern

Quality Score

Overall Score: 9.2/10 ⭐ Excellent

  • Technical Accuracy: 32/35
  • Code Quality: 25/25
  • Educational Value: 22/25
  • Documentation: 13/15

Last reviewed: August 18, 2026

The adapter pattern is a structural design pattern that allows object with incompatible interfaces to work together, transforming the original interface into a compatible interface. It is often used to make existing classes work with others without modifying their source code. The benefits of this pattern are:

  • Reusability: The adapter pattern allows for the reuse of existing classes, making it easier to integrate them into new systems.
  • Flexibility: The adapter pattern allows for flexibility in the design of the system, allowing for the use of different classes with different interfaces.

The adapter pattern is composed of three main components:

Target interface

The target interface represents the interface that the client expects. It defines the methods that the adapter class must implement to be compatible with the client.

src.advanced.adapter_pattern.AuthenticationInterface

Bases: ABC

Target interface expected by modern authentication clients.

Authentication is provided through a signed JWT (JSON Web Token), so it is compatible with modern authentication methods such as OAuth2 and OpenID Connect. Any interface not compatible with this new interface will need to be adapted.

Source code in src/advanced/adapter_pattern/adapter.py
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class AuthenticationInterface(ABC):
    """Target interface expected by modern authentication clients.

    Authentication is provided through a signed JWT (JSON Web Token), so it
    is compatible with modern authentication methods such as OAuth2 and
    OpenID Connect. Any interface not compatible with this new interface
    will need to be adapted.
    """

    @abstractmethod
    def authenticate(self, jwt: str) -> bool:
        """Authenticate a request based on the supplied JWT.

        Args:
            jwt: The JWT token to validate.

        Returns:
            True when the token grants access, False otherwise.

        Raises:
            ValueError: When the token is malformed or its signature does
                not verify.
        """

Adapter implementation

The adapter implementation is the class that implements the target interface and adapts the existing class to the target interface. It has a reference to the existing class and implements the methods of the target interface, transforming the original interface into a compatible interface.

src.advanced.adapter_pattern.LoginAdapter

Bases: AuthenticationInterface

Adapt the Login class to the new AuthenticationInterface interface.

Attributes:

Name Type Description
JWT_LENGTH

Number of dot-separated segments expected in a JWT.

login

The wrapped legacy Login used for credential checks.

Source code in src/advanced/adapter_pattern/adapter.py
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
class LoginAdapter(AuthenticationInterface):
    """Adapt the Login class to the new AuthenticationInterface interface.

    Attributes:
        JWT_LENGTH: Number of dot-separated segments expected in a JWT.
        login: The wrapped legacy Login used for credential checks.
    """

    JWT_LENGTH = 3

    def __init__(self, login: Login) -> None:
        """Initialize the adapter with the wrapped Login.

        Args:
            login: The legacy Login to delegate credential checks to.
        """
        self.login = login

    def authenticate(self, jwt: str) -> bool:
        """Authenticate a request based on the JWT with the Login interface.

        Args:
            jwt: The JWT token to validate.

        Returns:
            True when the username/password claims match the
            credentials expected by the wrapped Login, False otherwise.

        Raises:
            ValueError: When the JWT is malformed or is missing
            the username/password claims.

        """
        jwt_items = jwt.split(".")
        if len(jwt_items) != self.JWT_LENGTH:
            raise ValueError("Invalid JWT token format")

        try:
            payload_b64 = jwt_items[1]
            payload = json.loads(base64.urlsafe_b64decode(payload_b64 + "=="))
            username = payload["username"]
            password = payload["password"]
        except (json.JSONDecodeError, KeyError) as exc:
            raise ValueError("Missing JWT credentials") from exc

        return self.login.post(username, password)

Adaptee

The adaptee is the existing class that needs to be adapted to the target interface, which has an incompatible interface.

src.advanced.adapter_pattern.Login

Login class.

It is the adaptee interface that we want to adapt to a new interface.

Source code in src/advanced/adapter_pattern/adapter.py
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Login:
    """Login class.

    It is the adaptee interface that we want to adapt to a new interface.
    """

    EXPECTED_USERNAME = "admin"
    EXPECTED_PASSWORD = "admin"  # noqa: S105

    def post(self, username: str, password: str) -> bool:
        """Authenticate a user with plain username and password.

        Args:
            username: The username sent by the client.
            password: The password sent by the client.

        Returns:
            True when the credentials are expected, False otherwise.
        """
        return (
            username == self.EXPECTED_USERNAME
            and password == self.EXPECTED_PASSWORD
        )

The real world applications of the adapter pattern are: supporting legacy systems, reusing existing code that is hard to modify (complex or closed-source), wrapping third-party libraries...