Adapter Pattern
StructuralWhat is it?
Allows objects with incompatible interfaces to work together by wrapping an object with an interface that the client expects.
Why use it?
The Adapter pattern allows incompatible interfaces to work together. It acts as a bridge between two incompatible interfaces, allowing classes to work together that couldn't otherwise because of incompatible interfaces. This is especially useful when integrating new code with old code or third-party libraries.
Code Example
typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Adapter Pattern Example
// Old payment interface (legacy code)
class OldPaymentSystem {
makePayment(amount) {
console.log(`Processing payment of $${amount} through legacy system`);
return {
success: true,
transactionId: Math.random().toString(36).substr(2, 9)
};
}
}
// New payment interface that our application expects
class ModernPaymentInterface {
processPayment(paymentDetails) {
throw new Error('Method must be implemented');
}
}
// Third-party payment service with different interface
class StripePaymentService {
chargeCard(cardNumber, amount, currency) {
console.log(`Charging ${currency}${amount} to card ${cardNumber.slice(-4)}`);
return {
status: 'succeeded',
chargeId: 'ch_' + Math.random().toString(36).substr(2, 9)
};
}
}
// Adapter for old payment system
class OldPaymentAdapter extends ModernPaymentInterface {
constructor() {
super();
this.oldSystem = new OldPaymentSystem();
}
processPayment(paymentDetails) {
// Adapt the modern interface to the old system
const result = this.oldSystem.makePayment(paymentDetails.amount);
return {
status: result.success ? 'completed' : 'failed',
transactionId: result.transactionId,
amount: paymentDetails.amount,
currency: paymentDetails.currency || 'USD'
};
}
}
// Adapter for Stripe payment service
class StripeAdapter extends ModernPaymentInterface {
constructor() {
super();
this.stripe = new StripePaymentService();
}
processPayment(paymentDetails) {
// Adapt the modern interface to Stripe's interface
const result = this.stripe.chargeCard(
paymentDetails.cardNumber,
paymentDetails.amount,
paymentDetails.currency
);
return {
status: result.status === 'succeeded' ? 'completed' : 'failed',
transactionId: result.chargeId,
amount: paymentDetails.amount,
currency: paymentDetails.currency
};
}
}
// Payment processor that works with any payment service through adapters
class PaymentProcessor {
constructor(paymentAdapter) {
this.adapter = paymentAdapter;
}
process(paymentDetails) {
console.log('Processing payment...');
const result = this.adapter.processPayment(paymentDetails);
console.log('Payment result:', result);
return result;
}
}
// Usage
const paymentDetails = {
amount: 100,
currency: 'USD',
cardNumber: '4111111111111111'
};
// Using old payment system through adapter
const oldPaymentProcessor = new PaymentProcessor(new OldPaymentAdapter());
oldPaymentProcessor.process(paymentDetails);
// Using Stripe through adapter
const stripeProcessor = new PaymentProcessor(new StripeAdapter());
stripeProcessor.process(paymentDetails);
// Another example: Adapting different data formats
class XMLDataSource {
getXMLData() {
return `<users>
<user>
<name>John Doe</name>
<email>john@example.com</email>
</user>
<user>
<name>Jane Smith</name>
<email>jane@example.com</email>
</user>
</users>`;
}
}
class JSONDataAdapter {
constructor(xmlDataSource) {
this.xmlSource = xmlDataSource;
}
getData() {
const xmlData = this.xmlSource.getXMLData();
// Simplified conversion(in real app, use proper XML parser)
return {
users: [
{ name: 'John Doe', email: 'john@example.com' },
{ name: 'Jane Smith', email: 'jane@example.com' }
]
};
}
}
// Usage
const xmlSource = new XMLDataSource();
const jsonAdapter = new JSONDataAdapter(xmlSource);
const jsonData = jsonAdapter.getData();
console.log('Adapted data:', jsonData);
Quick Facts
- Category
- Structural
- Common Use Cases
- Object composition, interface adaptation