Real-World Adapter Patterns
API Version Adapter
Adapt between API versions:
typescript1interface ShippingServiceV2 {2 createShipment(request: ShipmentRequestV2): ShipmentResponseV2;3}45// Adapt old V1 API to new V2 interface6class V1toV2Adapter implements ShippingServiceV2 {7 constructor(private v1Service: ShippingServiceV1) {}89 createShipment(request: ShipmentRequestV2): ShipmentResponseV2 {10 const v1Request = this.downgradeRequest(request);11 const v1Response = this.v1Service.createShipment(v1Request);12 return this.upgradeResponse(v1Response);13 }1415 private downgradeRequest(v2: ShipmentRequestV2): ShipmentRequestV1 {16 return {17 from: v2.origin,18 to: v2.destination,19 weight: v2.packages[0]?.weight ?? 020 };21 }22}
Data Format Adapter
Convert between data formats:
typescript1interface AddressNormalizer {2 normalize(input: unknown): NormalizedAddress;3}45class XMLAddressAdapter implements AddressNormalizer {6 normalize(xml: string): NormalizedAddress {7 const parsed = parseXML(xml);8 return {9 street: parsed.querySelector('street')?.textContent ?? '',10 city: parsed.querySelector('city')?.textContent ?? '',11 // ...12 };13 }14}1516class JSONAddressAdapter implements AddressNormalizer {17 normalize(json: string): NormalizedAddress {18 const data = JSON.parse(json);19 return {20 street: data.address_line_1,21 city: data.city_name,22 // Map different field names23 };24 }25}
Event System Adapter
Adapt between event systems:
typescript1interface EventEmitter {2 on(event: string, handler: Function): void;3 emit(event: string, data: unknown): void;4}56// Adapt DOM events to custom event system7class DOMEventAdapter implements EventEmitter {8 constructor(private element: HTMLElement) {}910 on(event: string, handler: Function): void {11 this.element.addEventListener(event, (e) => handler(e.detail));12 }1314 emit(event: string, data: unknown): void {15 this.element.dispatchEvent(new CustomEvent(event, { detail: data }));16 }17}
Testing with Adapters
Create mock adapters for testing:
typescript1class MockShippingAdapter implements ShippingService {2 public calls: Array<{ from: Address; to: Address }> = [];34 getRate(from: Address, to: Address): Rate {5 this.calls.push({ from, to });6 return { amount: 10.00, currency: 'USD' };7 }89 createLabel(): Label {10 return { trackingNumber: 'MOCK123', url: 'http://mock' };11 }12}1314// In tests15const mockAdapter = new MockShippingAdapter();16const service = new OrderService(mockAdapter);17await service.processOrder(order);18expect(mockAdapter.calls).toHaveLength(1);
Summary
Adapters are essential for:
- Third-party API integration
- Legacy system migration
- Data format conversion
- Testing isolation