Skip to main content

Definition

“Adapter pattern converts the interface of a class into another that the clients expect, making classes with incompatible interfaces able to work together”
adapter

Explanation

You have an existing class (Adaptee) with one interface, but the client expects a different interface (Target). The Adapter class implements the Target interface and holds an instance of Adaptee. Its methods translate calls from the Target interface to calls on the Adaptee. This way, the client can use the adaptee through the adapter as if it were a different type.

Code

The Adapter pattern is a structural design pattern that allows objects with incompatible interfaces to collaborate. It wraps an object with an adapter to provide a different interface to clients. In this example, Adapter makes Adaptee’s interface compatible with Target’s interface. Client code can call request() on an Adapter, which internally calls specific_request() of Adaptee and processes its output.
class Target:
    def request(self) -> str:
        return "Target: The default target's behavior."

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

class Adapter(Target, Adaptee):
    def request(self) -> str:
        # Converts Adaptee's interface to Target's interface
        return f"Adapter: (TRANSLATED) {self.specific_request()[::-1]}"

def client_code(target: Target) -> None:
    print(target.request(), end="")

def main():
    print("Client: I can work just fine with Target objects:")
    target = Target()
    client_code(target)
    print("\n")

    adaptee = Adaptee()
    print("Client: The Adaptee has a weird interface:")
    print(f"Adaptee: {adaptee.specific_request()}", end="\n\n")

    print("Client: But I can work with it via the Adapter:")
    adapter = Adapter()
    client_code(adapter)
    print()

if __name__ == "__main__":
    main()

Analogy

A travel power adapter: your device has, say, a European plug, but the wall socket is American. The adapter wraps the plug and converts it to the necessary interface. Or a card reader: think of the client expecting an SD card interface, but you have a USB stick (adaptee); the adapter lets the USB stick pretend to be an SD card.

Interview Insights

Use Case: When integrating with a legacy or third-party class with an incompatible interface, or when you need to use existing classes in a new context. Also used to work around inability to change interfaces (e.g. vendor library).
Advantages: Allows reuse of existing code without modification. Separates interface from implementation.
Disadvantages: Can add overhead/wrapping code. If client and adaptee interfaces change, adapter must be updated. Using many adapters can complicate code structure.
Common questions:“Bridge vs Adapter: (Adapter fixes one existing interface, Bridge is for future extensibility)”, “Give examples (e.g. printer drivers, GUI toolkits)”, “Explain using UML, purpose of abstractions”.\