Introduction
The Adapter Pattern is a structural design pattern that allows objects with incompatible interfaces to work together. It acts as a bridge between two incompatible interfaces by wrapping one with another expected by the client.
Why Adapter Pattern Matters
In large-scale systems, you often need to integrate third-party APIs, legacy classes, or older components into your modern application. The Adapter Pattern enables this without modifying the original code—promoting reusability and clean separation of concerns.
Core Intent and Participants
- Intent: Convert the interface of a class into another interface that clients expect.
Participants
- Target: The interface expected by the client.
- Adapter: Translates requests from the Target to the Adaptee.
- Adaptee: Existing class with an incompatible interface.
- Client: Code that uses the Target interface.
UML Diagram (Text)
+----------+ +------------+ +-----------+
| Client | -----> | Target | <----- | Adapter |
+----------+ +------------+ +-----------+
|
|
+--------------+
| Adaptee |
+--------------+
Real-World Use Cases
- Integrating legacy payment gateways into a modern API
- Adapting third-party libraries (e.g., adapting a logging library to a common interface)
- Making different data sources (XML, JSON, DB) compatible with a common parser interface
- Wrapping a legacy
Enumeration
in Java to work withIterator
Implementation Strategies in Java
1. Object Adapter (Using Composition)
Step 1: Target Interface
public interface MediaPlayer {
void play(String audioType, String fileName);
}
Step 2: Adaptee
public class AdvancedMediaPlayer {
public void playVlc(String fileName) {
System.out.println("Playing VLC file: " + fileName);
}
public void playMp4(String fileName) {
System.out.println("Playing MP4 file: " + fileName);
}
}
Step 3: Adapter Class
public class MediaAdapter implements MediaPlayer {
private AdvancedMediaPlayer advancedPlayer = new AdvancedMediaPlayer();
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedPlayer.playVlc(fileName);
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedPlayer.playMp4(fileName);
} else {
System.out.println("Unsupported format: " + audioType);
}
}
}
Step 4: Client Code
public class AudioPlayer implements MediaPlayer {
private MediaAdapter mediaAdapter;
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3")) {
System.out.println("Playing MP3 file: " + fileName);
} else {
mediaAdapter = new MediaAdapter();
mediaAdapter.play(audioType, fileName);
}
}
}
public class AdapterDemo {
public static void main(String[] args) {
AudioPlayer player = new AudioPlayer();
player.play("mp3", "song.mp3");
player.play("vlc", "video.vlc");
player.play("avi", "movie.avi");
}
}
2. Class Adapter (Using Inheritance – not common in Java due to single inheritance)
public class ClassMediaAdapter extends AdvancedMediaPlayer implements MediaPlayer {
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("vlc")) {
playVlc(fileName);
} else if (audioType.equalsIgnoreCase("mp4")) {
playMp4(fileName);
}
}
}
✅ Prefer object adapter (composition) in most Java applications.
Pros and Cons
✅ Pros
- Promotes reusability of existing code
- Makes third-party or legacy code usable without modification
- Supports the Open/Closed Principle
❌ Cons
- May add unnecessary layers of abstraction
- Can increase system complexity if overused
- May lead to code duplication in adapter implementations
Anti-Patterns and Misuse
- Adapting too many interfaces with one adapter (violates SRP)
- Wrapping adapters around everything—use only when necessary
- Forgetting to validate data before adapting
Adapter vs Decorator vs Proxy
Pattern | Purpose | Modifies Interface? | Real-World Analogy |
---|---|---|---|
Adapter | Converts interface to expected one | ✅ Yes | Power plug adapter |
Decorator | Adds behavior to an object dynamically | ❌ No | Coffee with added sugar/flavor |
Proxy | Controls access to an object | ❌ No | Bank card (proxy to your bank) |
Refactoring Legacy Code
Before (Incompatible Interface)
LegacyPaymentProcessor legacyProcessor = new LegacyPaymentProcessor();
legacyProcessor.sendAmount(1000);
After (With Adapter)
PaymentAdapter adapter = new PaymentAdapter(legacyProcessor);
adapter.processPayment(1000);
✅ The rest of the system uses processPayment()
consistently.
Best Practices
- Use object adapters over class adapters in Java
- Clearly name adapters (e.g.,
XyzToAbcAdapter
) - Keep adapters minimal—do not add extra logic
- Ensure interface contracts are respected
Real-World Analogy
Imagine traveling from India to the US with a mobile charger. The Indian plug won’t fit in a US socket. Instead of replacing your charger, you use a plug adapter to bridge the incompatibility. That’s what the Adapter Pattern does in code.
Java Version Relevance
- Java 8+: Use default interface methods to bridge behaviors
- Java 11+: Adapting
HttpClient
vs olderHttpURLConnection
- Java 17+: Sealed classes can help limit what can be adapted
Conclusion & Key Takeaways
- The Adapter Pattern helps bridge incompatible interfaces.
- Ideal for integrating legacy or third-party code without rewriting it.
- Use composition-based adapters for maximum flexibility in Java.
- Avoid overuse and ensure your adapter’s role is clear and minimal.
FAQ – Adapter Pattern in Java
1. What is the Adapter Pattern?
It converts one interface into another that the client expects.
2. When should I use it?
When integrating incompatible or legacy code into your system.
3. What's the difference between object and class adapter?
Object adapter uses composition; class adapter uses inheritance.
4. Can I adapt multiple classes at once?
Yes, but ensure each class gets its own adapter if needed.
5. Is Adapter a structural pattern?
Yes, it's one of the structural patterns from GoF.
6. Can I use Adapter with interfaces?
Absolutely, it works best with interface-based designs.
7. Is Adapter the same as Wrapper?
Yes, Adapter is often referred to as a Wrapper.
8. Is Adapter Pattern used in Spring?
Yes, e.g., HandlerAdapter in Spring MVC.
9. Can it be combined with other patterns?
Yes, it often pairs with Facade, Proxy, or Composite.
10. How does Adapter affect performance?
Minimal impact. It's mostly a delegation layer.