Adapter
Adapter is a structural pattern that bridges two incompatible interfaces by sitting between them and translating calls. When the interface the client expects (Target) differs from the interface of the class you want to use (Adaptee), the Adapter converts calls between the two. It works just like a power plug adapter. You cannot plug a US plug into a Korean outlet, but with an adapter in between, the electricity flows just the same. In software, the Adapter's starting point is a situation where only the interface is mismatched while the underlying functionality is perfectly usable.
βΆArchitecture Diagram
π StructureDashed line animations indicate the flow direction of data or requests
As projects grow, the need to integrate external libraries, legacy modules, and third-party APIs becomes routine. The problem is that their interfaces do not match what your code expects. Method names differ, parameter orders differ, return types differ. If you modify the client code to match the external interface, then replacing the library later forces changes across the entire client. If you try to modify the external code, the source may not be available, or modifying it makes future updates difficult. You need a way to connect the two without touching either side.
Adapter is one of the 23 design patterns documented by GoF (Gang of Four) in 1994. As object-oriented programming became widespread, combining class libraries built by different teams grew common. With more commercial libraries whose source code could not be modified, a structural way to resolve interface mismatches without code changes became necessary. That pressure is identical today. npm packages, REST APIs, legacy microservices -- situations where 'it works but the interface does not fit' arise daily.
Adapter's core splits into three roles. The Client knows and calls only the Target interface's methods. The Adaptee has the actual functionality but exposes a different interface. The Adapter implements the Target interface and internally calls the Adaptee's methods, transforming results as needed. The sequence works like this: 1. The Client calls the Target interface's `request()`. 2. Inside the Adapter's `request()`, the Adaptee's `specificRequest()` is called. 3. The result from the Adaptee is transformed into the form the Client expects and returned. There are two implementation approaches. An object adapter holds the Adaptee as a field and delegates via composition. A class adapter inherits from the Adaptee and overrides methods. In most practical situations, composition is more flexible. Inheritance requires a language that supports multiple inheritance and tightly couples the Adapter to a single Adaptee.
Adapter and Facade both wrap existing code to expose a different interface, so they can look similar. But the intent differs. Adapter's purpose is to make one incompatible interface conform to an existing interface. The wrapping target is typically one object, and interface conversion is the core concern. Facade's purpose is to simplify multiple subsystems behind a single entry point. Adapter and Decorator are also structurally similar. Both wrap a target object, but Adapter changes the interface while Decorator keeps the interface the same and adds functionality. The test for whether Adapter is right is 'Is the problem that the interface does not fit?' If the issue is missing functionality rather than mismatched shape, Adapter is not the right tool.
Commonly Compared Concepts
Facade
A structural pattern that provides a simple entry point to a complex subsystem
Adapter converts one incompatible interface, while Facade groups multiple subsystems behind a single simplified entry point.
Decorator
A structural pattern that dynamically adds behavior to an object
Adapter changes the interface to a different shape, while Decorator keeps the same interface and adds behavior on top.
Proxy
A surrogate object that controls access to the real object
Adapter converts the interface for compatibility, while Proxy keeps the same interface and controls access.
Adapter appears most often at system boundaries. When replacing a payment gateway, you keep the existing `PaymentService` interface and wrap the new gateway's API with an Adapter so client code runs unchanged. The same approach works when switching ORMs or replacing an external authentication service. It is also useful in testing. Plugging a mock implementation into the same interface as the real HTTP client is a natural Adapter structure. However, if Adapters proliferate, it may be a signal to reconsider the interface design itself. If mismatches are structural, continually stacking conversion wrappers may be worse in the long run than redesigning a common interface.