Adapter Pattern
Type
Structural
Difficulty
★☆☆☆☆ (Low)
Definition
Convert an interface in to another interface clients expect, enabling incompatible classes to collaborate. Also known as Wrapper, it encapsulates a target class with a new layer, embodying the principle: "No problem can't be solved by adding one layer."
Use Cases
- When using an existing class with an incompatible interface, and modifying it is not feasible.
- When integrating independently developed modules with undetermined interfaces during initial design.
UML Roles
The pattern involves three core components:
- Target: Interface expected by client code.
- Adaptee: Existing class/interface with incompatible interface; provides required functionality.
- Adapter: Implements Target interface, wraps Adaptee to bridge compatibility gaps.
Implementation Example
Consider integrating a third-party logging library with an application's existing logger interface.
Step 1: Define Target Interface
Application's original logger contract:
public interface AppLogger {
void logDebug(String category, String content);
}
Step 2: Third-Party Logger Interface & Implementation
Incompatible external logger API:
public interface ExternalLogger {
void writeLog(int level, String msg, Object... args);
}
public class ExternalLoggerImpl implements ExternalLogger {
@Override
public void writeLog(int level, String msg, Object... args) {
System.out.printf("External Logger: %s%n", msg);
}
}
Step 3: Create Adapter Class
Bridges AppLogger and ExternalLogger:
import java.util.Objects;
public class LoggerAdapter implements AppLogger {
private final ExternalLogger externalLogger;
public LoggerAdapter(ExternalLogger externalLogger) {
this.externalLogger = Objects.requireNonNull(externalLogger);
}
@Override
public void logDebug(String category, String content) {
// Map app's debug call to external logger's level 1 (debug)
externalLogger.writeLog(1, content);
}
}
Step 4: Client Usage
public class LoggerClient {
public void executeLogging() {
AppLogger logger = new LoggerAdapter(new ExternalLoggerImpl());
logger.logDebug("System", "Integration test via adapter");
}
}
Key Technical Points
- Adapter must implement the Target interface.
- Adapter holds a reference to the Adaptee instance to delegate functionalitty.
Pros and Cons
Pros
- Enhances extensibility: Integrates new features without modifying existing interfaces.
Cons
- Introduces an additional abstraction layer, which may marginally increase complexity.