Adapter
Allows objects with incompatible interfaces to collaborate.
Context
You want to use an external or legacy library whose API doesn't fit your domain's abstraction.
Problem
- Modifying the external library is not an option.
- Scattering inline adaptations pollutes the domain.
Solution
An Adapter implements the interface your client expects and translates calls to the existing API.
#Example in C#
// Your domain expects this interface
public interface IPaymentGateway { Task<bool> ChargeAsync(decimal amount, string currency); }
// Third-party SDK
public class StripeSdk
{
public Task<StripeResult> CreateCharge(int amountCents, string iso) => /* ... */ Task.FromResult(new StripeResult(true));
}
public record StripeResult(bool Ok);
public class StripeAdapter : IPaymentGateway
{
private readonly StripeSdk _sdk;
public StripeAdapter(StripeSdk sdk) => _sdk = sdk;
public async Task<bool> ChargeAsync(decimal amount, string currency)
{
var result = await _sdk.CreateCharge((int)(amount * 100), currency.ToUpperInvariant());
return result.Ok;
}
}When NOT to use it
If you control both parties, it's better to unify the interfaces and eliminate the adapter.
Tradeoffs
| Pro | Con |
|---|---|
| Isolates external dependency | One more layer of indirection |
| Allows swapping providers | Risk of leaking SDK concepts into the adapter |
#Variants
- Object Adapter (composition — the example above).
- Class Adapter (multiple inheritance — limited in C# by the lack of multiple class inheritance).
#structural #gof #wrapper