Low-level design2 min
Adapter Pattern
Type: Structural Pattern
Relevance: High. You will use this often when integrating third-party libraries or legacy code.
The Adapter pattern allows objects with incompatible interfaces to collaborate. It acts as a wrapper that catches calls to one object and transforms them to format and interface recognizable by the second object.
Real-Life Analogy
Think of a Travel Power Plug Adapter. If you travel from the USA (which uses Type A/B flat pins) to Europe (which uses Type C round pins), you cannot plug your laptop directly into the wall. You use a power adapter. The adapter has a Type A socket on one side (which your laptop plugs into) and Type C pins on the other (which plugs into the wall). It adapts the interface so the two incompatible systems can work together.
The Problem
Imagine you have a stock market app that downloads data in XML format and displays beautiful charts. You want to integrate a 3rd-party analytics library, but it only accepts data in JSON format. You can't change the 3rd-party library (it's closed source), and you don't want to rewrite your entire app to use JSON.
How to Implement Adapter
Create an Adapter class that implements the interface your application expects. Inside the Adapter, wrap the 3rd-party object. When your app calls a method on the Adapter using XML, the Adapter translates it to JSON and passes it to the wrapped object.
Example in Code
// 1. The Target Interface (What your app expects to use)
interface JSONAnalytics {
analyzeData(jsonData: string): void;
}
// 2. The Adaptee (The incompatible 3rd-party library)
class XMLAnalyticsLibrary {
public processXML(xmlData: string): void {
console.log(`Processing XML Data: ${xmlData}`);
}
}
// 3. The Adapter (The Bridge between the two)
class XMLToJSONAdapter implements JSONAnalytics {
private adaptee: XMLAnalyticsLibrary;
constructor(adaptee: XMLAnalyticsLibrary) {
this.adaptee = adaptee;
}
// Implementing the target interface
public analyzeData(jsonData: string): void {
console.log(`Adapter: Converting JSON (${jsonData}) to XML...`);
const xmlData = "<data>converted_from_json</data>";
// Delegating to the Adaptee
this.adaptee.processXML(xmlData);
}
}
// Client Code
// The client only knows how to speak JSON.
const analyticsLib = new XMLAnalyticsLibrary();
const adapter = new XMLToJSONAdapter(analyticsLib);
adapter.analyzeData("{ 'data': 'json' }");
Class Diagram
Why is it Important?
- Single Responsibility: You separate the data conversion logic from the primary business logic.
- Open/Closed Principle: You can introduce new adapters without breaking existing client code.