Skip to main content

What It Is

The Adapter pattern makes a type with the wrong interface fit the interface your code expects — like a travel plug between a foreign socket and your charger.

You cannot change the old type (it comes from a library, or other code depends on it). So you wrap it in a small type that implements the interface you need and translates the calls.


Example: An Old Printer as a Logger

Our code wants a Logger with Log(message). The legacy type only offers WriteLine(prefix, text). The adapter holds the old type and translates one call into the other.

The adapter translates the call

run() works with any Logger; the adapter makes the legacy printer one of them without touching its code.

Prompt
Write a Go program with a Logger interface (Log method) that our run function expects, a LegacyPrinter with a different WriteLine(prefix, text) method that cannot be changed, and a PrinterAdapter that implements Logger by translating to WriteLine. Run the service with the adapter.
Output: Go program and captured output
The adapter translates the call

When to Use It

Use it when working code and a needed interface do not match, and you cannot (or should not) change either side — third-party libraries, legacy code, generated code.

Skip it when you own both sides — then just change one of them to match. An adapter between two types you control is a workaround for a decision you could simply make.


Pros and Cons

Pros: old and new code cooperate without changes to either; the translation lives in one small, testable type.

Cons: one more hop to read through; many adapters stacked on each other are a sign the interfaces themselves need rework.