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.
As teams grow and pull in more external libraries and APIs, the same friction keeps surfacing: the functionality is right, but the calling shape is wrong. A payment module expects charge(), the new SDK exposes pay(), your internal code passes a User object, and the external API wants { firstName, lastName }. The less control you have over the foreign code, the more urgently that mismatch has to be absorbed somewhere else.
Adapter comes from that pressure. Instead of rewriting either side, you introduce a conversion layer in the middle that absorbs the interface difference structurally. GoF documented it in 1994, but in a world of npm packages, REST APIs, and legacy services, it is still an almost daily problem.
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.
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.