Course contentsShow
← Rust
Lesson 614 of 1,9105. Type System and TraitsFree lesson

The Adapter Pattern for Legacy APIs

Translate disparate third-party interfaces into unified trait-based local interfaces.

In this lesson, you will learn how to wrap incompatible third-party interfaces into a consistent, trait-based API using the Adapter pattern.

The Problem: Legacy Mismatches

When integrating external libraries, you often find yourself dealing with "legacy" code—interfaces that don't match your project's internal design. Perhaps you have a system that expects a DataProcessor trait with a process(&self) method, but your third-party logging tool uses a completely different naming convention like emit_payload(data: String). You don't want to rewrite your business logic just because a library uses a different naming scheme.

The Solution: Creating an Adapter

Instead of forcing your codebase to change, you create a "wrapper" struct that implements your trait, holding the legacy object inside. This transforms the disparate interface into one that satisfies your internal requirements.

Consider this example:

// Our internal expected interface
trait Processor {
    fn process(&self);
}

// A third-party legacy struct we can't change
struct LegacyTool;
impl LegacyTool {
    fn run_old_routine(&self) { println!("Running legacy logic..."); }
}

// The Adapter
struct Adapter(LegacyTool);

// Translating the interface
impl Processor for Adapter {
    fn process(&self) {
        // We map our trait method to the legacy implementation
        self.0.run_old_routine();
    }
}

Why This Matters

By using this pattern, your core application code remains decoupled from the implementation details of the third-party crate. Your main logic only talks to the Processor trait. If you decide to switch to a newer, better library in the future, you don’t have to touch your application code; you simply write a new Adapter struct that maps the new library’s methods to your Processor trait.

This allows you to maintain a clean, unified internal API while insulating your codebase from the quirks of external dependencies. It treats the legacy interface as a black box and creates a standardized "bridge" that aligns with your domain's architecture.

Key Takeaway: The Adapter pattern uses trait implementation on a wrapper struct to map foreign method signatures onto your own internal trait requirements, shielding your code from external API drift.