The Bridge pattern is a structural design pattern that decouples an abstraction from its implementation so that both can vary independently. It avoids a permanent binding between an abstraction and its implementation, enabling them to evolve separately.
Core Intent
“Decouple an abstraction from its implementation so that the two can vary independently.”
This prevents an explosion of classes when you have multiple dimensions of variation (e.g., UI theme + platform, payment method + gateway).
When to Use Bridge
| Scenario | Use Case |
|---|---|
| Multiple orthogonal dimensions of variation | e.g., Shape + Renderer, Device + Remote |
| Want to avoid inheritance explosion | No need for WindowsDarkButton, MacLightButton, etc. |
| Implementation must be swappable at runtime | Change renderer/theme dynamically |
| Abstraction and implementation evolve separately | UI team vs rendering engine team |
| Share implementation among multiple objects | One renderer for many shapes |
Avoid when:
- Only one dimension varies → Use simple inheritance
- Performance is ultra-critical → Slight indirection cost
Where It Is Used in Real Systems
| Domain | Example |
|---|---|
| Graphics/UI | Shapes (Circle, Square) + Renderers (Vector, Raster) |
| Drivers | Device (TV, Radio) + Remote (Basic, Advanced) |
| Databases | JDBC: Driver (abstraction) + OracleDriver, MySQLDriver |
| E-Commerce | PaymentMethod (CreditCard, UPI) + Gateway (Razorpay, Stripe) |
| Game Engines | Weapon + FiringMode |
Key Benefits
- Single Responsibility: Abstraction and implementation separate
- Open/Closed Principle: Extend either side independently
- Runtime switching: Change implementation dynamically
- Reduced class count: No combinatorial explosion
- Testability: Mock implementations easily
Real-World Example: E-Commerce Multi-Gateway Payment System
We need to support:
- Payment methods: Credit Card, UPI, NetBanking
- Gateways: Razorpay, Stripe, PayPal
Without Bridge → 9 classes (CreditCardRazorpay, UPIPayPal, etc.)
With Bridge → only 3 + 3 = 6 classes, and we can:
- Add new method/gateway independently
- Switch gateway at runtime per customer preference
C# Implementation
using System;
// ==================== IMPLEMENTOR (BRIDGE) ====================
public interface IPaymentGateway
{
bool Initialize(decimal amount, string currency);
string GeneratePaymentUrl(string returnUrl);
bool VerifyPayment(string gatewayReference);
string GetGatewayName();
}
// ==================== CONCRETE IMPLEMENTORS ====================
public class RazorpayGateway : IPaymentGateway
{
public bool Initialize(decimal amount, string currency)
{
Console.WriteLine($"[Razorpay] Initializing payment ₹{amount} {currency}");
return true;
}
public string GeneratePaymentUrl(string returnUrl)
=> $"https://razorpay.com/pay/{Guid.NewGuid():N}?return={returnUrl}";
public bool VerifyPayment(string gatewayReference)
=> gatewayReference.StartsWith("pay_");
public string GetGatewayName() => "Razorpay";
}
public class StripeGateway : IPaymentGateway
{
public bool Initialize(decimal amount, string currency)
{
Console.WriteLine($"[Stripe] Creating PaymentIntent for ${amount} {currency}");
return true;
}
public string GeneratePaymentUrl(string returnUrl)
=> $"https://checkout.stripe.com/{Guid.NewGuid():N}";
public bool VerifyPayment(string gatewayReference)
=> gatewayReference.StartsWith("pi_");
public string GetGatewayName() => "Stripe";
}
public class PayPalGateway : IPaymentGateway
{
public bool Initialize(decimal amount, string currency)
{
Console.WriteLine($"[PayPal] Creating order for ${amount} {currency}");
return true;
}
public string GeneratePaymentUrl(string returnUrl)
=> $"https://paypal.com/checkout/{Guid.NewGuid():N}";
public bool VerifyPayment(string gatewayReference)
=> gatewayReference.StartsWith("PAYID-");
public string GetGatewayName() => "PayPal";
}
// ==================== ABSTRACTION ====================
public abstract class PaymentMethod
{
protected IPaymentGateway Gateway;
protected PaymentMethod(IPaymentGateway gateway)
{
Gateway = gateway ?? throw new ArgumentNullException(nameof(gateway));
}
public abstract string Process(decimal amount, string currency, string returnUrl);
public abstract bool ValidatePayment(string gatewayRef);
public abstract string GetMethodName();
}
// ==================== REFINED ABSTRACTIONS ====================
public class CreditCardPayment : PaymentMethod
{
public CreditCardPayment(IPaymentGateway gateway) : base(gateway) { }
public override string Process(decimal amount, string currency, string returnUrl)
{
if (!Gateway.Initialize(amount, currency)) return null;
Console.WriteLine($"[CreditCard] Collecting card details...");
return Gateway.GeneratePaymentUrl(returnUrl);
}
public override bool ValidatePayment(string gatewayRef)
=> Gateway.VerifyPayment(gatewayRef);
public override string GetMethodName() => "Credit Card";
}
public class UPIPayment : PaymentMethod
{
public UPIPayment(IPaymentGateway gateway) : base(gateway) { }
public override string Process(decimal amount, string currency, string returnUrl)
{
if (!Gateway.Initialize(amount, currency)) return null;
Console.WriteLine($"[UPI] Generating QR / VPA...");
return Gateway.GeneratePaymentUrl(returnUrl);
}
public override bool ValidatePayment(string gatewayRef)
=> Gateway.VerifyPayment(gatewayRef);
public override string GetMethodName() => "UPI";
}
// ==================== CLIENT ====================
public class CheckoutService
{
public string Checkout(PaymentMethod paymentMethod, decimal amount, string currency = "INR")
{
string returnUrl = "https://yoursite.com/success";
string paymentUrl = paymentMethod.Process(amount, currency, returnUrl);
return $"Redirect to: {paymentUrl}\n" +
$"Method: {paymentMethod.GetMethodName()} via {paymentMethod.Gateway.GetGatewayName()}";
}
}
// ==================== DEMO ====================
class Program
{
static void Main()
{
Console.WriteLine("=== BRIDGE PATTERN IN E-COMMERCE ===\n");
var checkout = new CheckoutService();
// Runtime composition — no fixed binding!
var payments = new PaymentMethod[]
{
new CreditCardPayment(new RazorpayGateway()),
new UPIPayment(new RazorpayGateway()),
new CreditCardPayment(new StripeGateway()),
new UPIPayment(new PayPalGateway())
};
decimal amount = 2499.00m;
int i = 1;
foreach (var payment in payments)
{
Console.WriteLine($"Option {i++}:");
Console.WriteLine(checkout.Checkout(payment, amount));
Console.WriteLine("─".PadRight(60, '─'));
}
}
}Sample Output
=== BRIDGE PATTERN IN E-COMMERCE ===
Option 1:
[Razorpay] Initializing payment ₹2499 INR
[CreditCard] Collecting card details...
Redirect to: https://razorpay.com/pay/a1b2c3d4e5f6...?return=...
Method: Credit Card via Razorpay
────────────────────────────────────────────────────────────
Option 2:
[Razorpay] Initializing payment ₹2499 INR
[UPI] Generating QR / VPA...
Redirect to: https://razorpay.com/pay/x9y8z7...
Method: UPI via Razorpay
────────────────────────────────────────────────────────────
...UML Class Diagram

Participants in the Bridge Pattern
| Participant | Role in E-Commerce Example |
|---|---|
| Abstraction | PaymentMethod – high-level payment flow |
| RefinedAbstraction | CreditCardPayment, UPIPayment |
| Implementor | IPaymentGateway – low-level execution |
| ConcreteImplementor | RazorpayGateway, StripeGateway, PayPalGateway |
| Client | CheckoutService – composes abstraction + implementor |
Summary
| Participant | E-Commerce Role |
|---|---|
| Abstraction | PaymentMethod |
| RefinedAbstraction | CreditCardPayment, UPIPayment |
| Implementor | IPaymentGateway |
| ConcreteImplementor | RazorpayGateway, StripeGateway |
| Client | CheckoutService |
Bridge vs Adapter
| Feature | Bridge | Adapter |
|---|---|---|
| Purpose | Design-time decoupling | Integrate existing incompatible code |
| When decided | Upfront, during design | After systems exist |
| Both sides vary? | Yes | Usually only adaptee fixed |
| Example | PaymentMethod + Gateway | Wrap legacy API |
Conclusion
The Bridge pattern is perfect for e-commerce when you have two or more independent dimensions (payment method × gateway, theme × renderer, device × protocol). It prevents class explosion and allows full runtime flexibility.
Used in:
- JDBC drivers
- Spring Cloud Gateway
- UI frameworks (SkiaSharp + Canvas, WPF + DirectX)
- Payment orchestrators in Shopify, Stripe, Razorpay integrations
Master Bridge = Future-proof your multi-vendor integrations!




