π€ What Is the Adapter Pattern?
The Adapter Pattern is a structural design pattern that allows objects with incompatible interfaces to work together. It acts as a bridge between two different systems by wrapping one interface inside another.
Think of it as a plug adapter that lets a foreign device connect to a local socket.
π¦ When to Use It
Use the Adapter Pattern when:
You want to reuse existing classes without modifying their source code
You need to integrate with third-party APIs that donβt match your expected interface
You are migrating from legacy systems and need to maintain backward compatibility
Typical scenarios:
Wrapping old code with a modern interface
Adapting third-party libraries to your domain model
Integrating services with mismatched contracts
π οΈ How It Works
The Adapter Pattern includes:
A client expecting a specific interface
A legacy or incompatible class with a different interface
An adapter that translates the incompatible interface into the one expected by the client
C# Example: Audio Player Adapting Media Formats
// Target interface
public interface IAudioPlayer
{
void Play(string fileName);
}
// Adaptee with a different interface
public class Mp4Player
{
public void PlayMp4(string fileName)
{
Console.WriteLine($"Playing MP4 file: {fileName}");
}
}
// Adapter
public class Mp4Adapter : IAudioPlayer
{
private readonly Mp4Player _mp4Player;
public Mp4Adapter(Mp4Player mp4Player)
{
_mp4Player = mp4Player;
}
public void Play(string fileName)
{
_mp4Player.PlayMp4(fileName);
}
}
Usage
IAudioPlayer player = new Mp4Adapter(new Mp4Player());
player.Play("song.mp4");
β Advantages
Promotes reusability by allowing incompatible interfaces to cooperate
Follows the Open/Closed Principle since you donβt modify existing code
Makes your system more flexible and extensible
β Disadvantages
Introduces extra layers which may affect performance
Can become complicated if too many adapters are used
May hide the limitations or quirks of the adapted code
π§ͺ Testing Benefits
You can mock the adapter interface for unit tests
Allows isolation of external libraries or legacy systems in your tests
Helps enforce separation of concerns by wrapping third-party logic
π Real-World Use Cases
Payment gateways: Wrapping various APIs into a common payment interface
Logging frameworks: Adapting one logging provider to match a custom interface
UI components: Bridging incompatible widgets in cross-platform toolkits
File systems: Abstracting platform-specific operations under a unified interface
π Related Patterns
Facade: Simplifies a subsystem but keeps interfaces compatible
Decorator: Adds new functionality while preserving the interface
Bridge: Decouples abstraction from implementation, while Adapter changes the interface
π― Final Thoughts
The Adapter Pattern lets you connect the dots between systems that were never designed to talk to each other. It is especially useful when working with legacy code, third-party APIs or integrating heterogeneous systems. Just be careful not to overuse adapters or wrap poorly designed code without addressing underlying issues.