Introduction to the Adapter Pattern

Welcome to our journey through Structural Patterns! Structural patterns help manage object compositions and relationships, aiding in the creation of more scalable and flexible systems. One foundational structural pattern is the Adapter Pattern, which focuses on enabling two incompatible interfaces to work together seamlessly. Imagine you have a European plug that you need to use with a U.S. socket. They are inherently incompatible, but through an adapter, you can bridge this gap. Similarly, in software design, you often encounter situations where you need to integrate classes with incompatible interfaces. The Adapter Pattern provides a way to achieve this integration.

Core Components of the Adapter Pattern

The key components of the Adapter Pattern include the Target Interface, the Adaptee, and the Adapter. The Target Interface is the interface expected by the client. In our example, this would be USPlug. The Adaptee is the existing interface that needs adapting, which in our case is EuropeanPlug. The Adapter is the class that bridges the gap between the Target Interface and the Adaptee.

Step 1: Define the Adaptee

We start by defining the Adaptee, which in our case is the EuropeanPlug. Here’s the initial code for the EuropeanPlug class:

The EuropeanPlug class has a connect method that logs a string indicating that the plug is connected. This is the starting point of our implementation.

Step 2: Define the Target Interface

In TypeScript, interfaces allow us to explicitly define the structure that a class must follow. Here, we define the USPlug interface, which specifies the expected connect method:

The USPlug interface establishes the contract that any compatible plug must implement a connect method. This makes it clear what the client expects.

Step 3: Create the Adapter

Now, we need to create the Adapter that will bridge the EuropeanPlug with the USPlug interface. In TypeScript, we implement the interface directly and use type annotations for clarity:

The Adapter class implements the USPlug interface, ensuring it provides the required connect method. The constructor accepts an instance of EuropeanPlug and uses it to fulfill the connect functionality.

Complete Code Example

Here’s how the complete code looks when you put all the components together in TypeScript:

This complete code demonstrates how we can use an Adapter to make a EuropeanPlug instance compatible with the USPlug interface. The use of TypeScript interfaces and type annotations ensures type safety and clarity throughout the implementation.

Conclusion

The Adapter Pattern is crucial for making incompatible interfaces compatible without changing their existing code. It offers a flexible solution for legacy code integration, third-party library usage, and cross-platform application development. By mastering the Adapter Pattern, you will be better equipped to handle real-world scenarios where you need to integrate different systems or components. This pattern enhances code reusability and maintainability, reducing the need to modify existing systems to fit together. Are you excited to see this pattern in action? Let’s move on to the practice section and implement it step by step.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal