The Adapter design pattern is a structural design pattern that allows incompatible classes to work together. The main purpose of the adapter is to convert the interface of a class into another interface that the client expects. This pattern allows classes to work together that would not otherwise be able to due to incompatible interfaces. The main idea behind this pattern is for the client to interact with the expected interface, which is not implemented directly by the service with which the client wants to interact, but by the adapter for this service. The adapter acts like a translation layer between incompatible interfaces. Translation details are hidden from the client using the interface. That way, the client can interact with the service, which normally would be incompatible with or would require changes in the client code.
The Adapter design pattern can be successfully applied in use cases when we have two already existing systems, libraries, or classes which need to be integrated, but the expected interface on how one part interacts with the other part is different. This is especially useful when one part, let’s call it X, interacts with the other parties, let’s call them A, B, and C; having X compatible with A and B, but incompatible interfaces with C, it might be the most optimal solution to implement an adapter for C to avoid changing existing interfaces that work for X->A and X->B. Notice that mentioned X, A, B, and C can be a system, library, or a set of classes. The following diagram depicts such a situation:
Example use cases include:
- Data Conversion: When working with different systems, which expect different data formats. One system produces XML data, which needs to be sent to the other system that expects JSON data.
- Service Integration: When integrating external services into the existing codebase, we may need to adapt the service’s interface to the interface expected by our system.
- Connecting different database technologies: Adapters can be used to connect to different databases, such as PostgreSQL, MySQL, and Oracle, with the same interface, allowing them to work together seamlessly.
- Third-Party Library Integration: We may need to integrate a third-party library into our system with an interface different from what our system expects. We can use an adapter to create a compatible interface in such cases.
- Legacy Code Integration: When we want to reuse an existing legacy code module that has an incompatible interface with the rest of the system, we can use an adapter to bridge the gap.
- Multi-Platform Support: In cases where we need to support multiple platforms, we can use adapters to provide a common interface that works across all platforms.
To read more on this and the other patterns, get “GoF Design Patterns Distilled” book from Amazon or Leanpub: