|
| 1 | +--- |
| 2 | +title: Bridge Pattern |
| 3 | +tags: |
| 4 | + - structural |
| 5 | +created: 2026-03-15 |
| 6 | +--- |
| 7 | +## Definition |
| 8 | + |
| 9 | +The **Bridge** is a structural design pattern that divides business logic or huge class into separate class hierarchies that can be developed independently. |
| 10 | + |
| 11 | +--- |
| 12 | +## Real World Analogy |
| 13 | + |
| 14 | +Imagine you are implementing a payment system in your application. Users should be able to pay using different payment methods such as **Credit Card**, **Debit Card**, **UPI**, or **Wallet**. However, the application itself does not implement the actual payment processing. Instead, it relies on third‑party payment gateways. |
| 15 | + |
| 16 | +There are multiple payment gateways available such as RazorPay, Stripe, or PayPal. Each gateway should be able to work with any payment method. |
| 17 | + |
| 18 | +If we tightly couple every payment method with every gateway, we would end up creating many classes like: |
| 19 | +```txt |
| 20 | +RazorPayCreditCardPayment |
| 21 | +RazorPayUPIPayment |
| 22 | +StripeCreditCardPayment |
| 23 | +StripeUPIPayment |
| 24 | +``` |
| 25 | + |
| 26 | +Now imagine adding a new gateway like `PhonePeGateway`. We would need to create additional classes for every payment method again. This quickly leads to a large number of classes and tightly coupled code. |
| 27 | + |
| 28 | +The **Bridge Pattern** solves this problem by separating the abstraction from its implementation so both can evolve independently. |
| 29 | + |
| 30 | +The pattern contains two major parts: |
| 31 | +- **Abstraction** – The high level layer that the client interacts with. |
| 32 | +- **Implementation** – The low level layer that performs the actual work. |
| 33 | + |
| 34 | +In this example: |
| 35 | +- **Payment Methods** act as the **Abstraction**. |
| 36 | +- **Payment Gateways** act as the **Implementation**. |
| 37 | + |
| 38 | +The bridge connects these two hierarchies so that any payment method can work with any payment gateway without creating multiple combinations of classes. |
| 39 | + |
| 40 | +--- |
| 41 | +### How Bridge Pattern is different from Strategy Pattern? |
| 42 | + |
| 43 | +The **Bridge Pattern** and **Strategy Pattern** both use composition, but they serve different purposes. |
| 44 | +The **Bridge Pattern** is used to **separate an abstraction from its implementation so that both can change independently**. It is especially useful when there are **two dimensions that may vary**, such as payment methods and payment gateways. This prevents creating many subclasses for every combination. |
| 45 | +In contrast, the **Strategy Pattern** is used to **define multiple algorithms and allow switching between them at runtime**. Its primary goal is to change behavior dynamically, for example selecting different sorting algorithms or payment calculation logic. |
| 46 | + |
| 47 | +--- |
| 48 | +## Design |
| 49 | + |
| 50 | +The following class diagram shows how the Bridge pattern separates the **Payment type hierarchy** from the **Payment gateway hierarchy**. Both hierarchies are connected through a bridge using composition. |
| 51 | + |
| 52 | +This design ensures that new payment methods or new gateways can be added without modifying existing classes. Each hierarchy can grow independently. |
| 53 | + |
| 54 | +```mermaid |
| 55 | +classDiagram |
| 56 | +class Payment { |
| 57 | + #PaymentGateway paymentGateway |
| 58 | + +Payment(PaymentGateway gateway) |
| 59 | + +makePayment(double amount)* |
| 60 | +} |
| 61 | +
|
| 62 | +class CreditCardPayment { |
| 63 | + +makePayment(double amount) |
| 64 | +} |
| 65 | +
|
| 66 | +class UPIPayment { |
| 67 | + +makePayment(double amount) |
| 68 | +} |
| 69 | +
|
| 70 | +class WalletPayment { |
| 71 | + +makePayment(double amount) |
| 72 | +} |
| 73 | +
|
| 74 | +class PaymentGateway { |
| 75 | + <<interface>> |
| 76 | + +processPayment(double amount) |
| 77 | +} |
| 78 | +
|
| 79 | +class RazorPayPaymentGateway { |
| 80 | + +processPayment(double amount) |
| 81 | +} |
| 82 | +
|
| 83 | +class StripePaymentGateway { |
| 84 | + +processPayment(double amount) |
| 85 | +} |
| 86 | +
|
| 87 | +class PayPalPaymentGateway { |
| 88 | + +processPayment(double amount) |
| 89 | +} |
| 90 | +
|
| 91 | +Payment <|-- CreditCardPayment |
| 92 | +Payment <|-- UPIPayment |
| 93 | +Payment <|-- WalletPayment |
| 94 | +
|
| 95 | +Payment --> PaymentGateway : uses |
| 96 | +
|
| 97 | +PaymentGateway <|.. RazorPayPaymentGateway |
| 98 | +PaymentGateway <|.. StripePaymentGateway |
| 99 | +PaymentGateway <|.. PayPalPaymentGateway |
| 100 | +``` |
| 101 | + |
| 102 | +_Class Diagram for the Payment System using the Bridge pattern_ |
| 103 | + |
| 104 | +--- |
| 105 | +## Implementation in Java |
| 106 | + |
| 107 | +```java title="PaymentGateway.java" |
| 108 | +interface PaymentGateway { |
| 109 | + void processPayment(double amount); |
| 110 | +} |
| 111 | +``` |
| 112 | + |
| 113 | +This interface represents the **implementation side** of the Bridge pattern. All payment gateways must implement this interface so that the abstraction layer can use them without depending on a specific gateway. |
| 114 | +```java title="RazorPayPaymentGateway.java" |
| 115 | +class RazorPayPaymentGateway implements PaymentGateway{ |
| 116 | + @Override |
| 117 | + public void processPayment(double amount) { |
| 118 | + System.out.println(String.format("Processing the Payment For Amount=%s Via RazorPay",amount |
| 119 | + )); |
| 120 | + } |
| 121 | +} |
| 122 | +``` |
| 123 | +This class is a concrete implementation of the `PaymentGateway` interface. It simulates processing the payment through RazorPay. |
| 124 | +```java title="StripePaymentGateway.java" |
| 125 | +class StripePaymentGateway implements PaymentGateway{ |
| 126 | + |
| 127 | + @Override |
| 128 | + public void processPayment(double amount) { |
| 129 | + System.out.println(String.format("Processing the Payment For Amount=%s Via Stripe",amount |
| 130 | + )); |
| 131 | + } |
| 132 | +} |
| 133 | +``` |
| 134 | +This class represents another gateway implementation. The abstraction layer does not need to know how Stripe works internally. |
| 135 | +```java title="PayPalPaymentGateway.java" |
| 136 | +class PayPalPaymentGateway implements PaymentGateway{ |
| 137 | + |
| 138 | + @Override |
| 139 | + public void processPayment(double amount) { |
| 140 | + System.out.println(String.format("Processing the Payment For Amount=%s Via PayPal",amount |
| 141 | + )); |
| 142 | + } |
| 143 | +} |
| 144 | +``` |
| 145 | +This class provides support for the PayPal payment gateway. Any payment type can use this gateway. |
| 146 | +```java title="Payment.java" |
| 147 | +abstract class Payment{ |
| 148 | + // Payment Supports any Payment Gateway acting as the bridge |
| 149 | + protected PaymentGateway paymentGateway; |
| 150 | + |
| 151 | + public Payment(PaymentGateway paymentGateway){ |
| 152 | + this.paymentGateway=paymentGateway; |
| 153 | + } |
| 154 | + |
| 155 | + abstract void makePayment(double amount); |
| 156 | +} |
| 157 | +``` |
| 158 | +This abstract class represents the **abstraction layer**. It contains a reference to `PaymentGateway`, which acts as the bridge between the payment type and the gateway implementation. |
| 159 | +```java title="CreditCardPayment.java" |
| 160 | +class CreditCardPayment extends Payment{ |
| 161 | + |
| 162 | + public CreditCardPayment(PaymentGateway paymentGateway){ |
| 163 | + // Calling the payment Abstract class |
| 164 | + super(paymentGateway); |
| 165 | + } |
| 166 | + |
| 167 | + @Override |
| 168 | + void makePayment(double amount) { |
| 169 | + System.out.println("Payment via CreditCard"); |
| 170 | + this.paymentGateway.processPayment(amount); |
| 171 | + } |
| 172 | +} |
| 173 | +``` |
| 174 | +This class represents a specific payment type. It uses the gateway object to actually process the payment. |
| 175 | +```java title="UPIPayment.java" |
| 176 | +class UPIPayment extends Payment{ |
| 177 | + public UPIPayment(PaymentGateway paymentGateway){ |
| 178 | + super(paymentGateway); |
| 179 | + } |
| 180 | + |
| 181 | + @Override |
| 182 | + void makePayment(double amount) { |
| 183 | + System.out.println("Payment via UPI"); |
| 184 | + this.paymentGateway.processPayment(amount); |
| 185 | + } |
| 186 | +} |
| 187 | +``` |
| 188 | +This class represents UPI payments. The logic of how the payment is processed is delegated to the gateway. |
| 189 | +```java title="WalletPayment.java" |
| 190 | +class WalletPayment extends Payment{ |
| 191 | + public WalletPayment(PaymentGateway paymentGateway){ |
| 192 | + super(paymentGateway); |
| 193 | + } |
| 194 | + |
| 195 | + @Override |
| 196 | + void makePayment(double amount) { |
| 197 | + System.out.println("Payment via Wallet"); |
| 198 | + this.paymentGateway.processPayment(amount); |
| 199 | + } |
| 200 | +} |
| 201 | +``` |
| 202 | +This class represents wallet based payments. Again, it uses the gateway bridge to complete the transaction. |
| 203 | +```java title="BridgePattern.java" |
| 204 | +public static void main(String[] args) { |
| 205 | + PaymentGateway razorpay = new RazorPayPaymentGateway(); |
| 206 | + PaymentGateway paypal = new PayPalPaymentGateway(); |
| 207 | + PaymentGateway stripe = new StripePaymentGateway(); |
| 208 | + |
| 209 | + Payment creditCardPayment = new CreditCardPayment(razorpay); |
| 210 | + creditCardPayment.makePayment(5000); |
| 211 | + |
| 212 | + System.out.println(); |
| 213 | + |
| 214 | + Payment upiPayment = new UPIPayment(paypal); |
| 215 | + upiPayment.makePayment(1500); |
| 216 | + |
| 217 | + System.out.println(); |
| 218 | + |
| 219 | + Payment walletPayment= new WalletPayment(stripe); |
| 220 | + walletPayment.makePayment(3400); |
| 221 | +} |
| 222 | +``` |
| 223 | +The client creates payment gateway objects and passes them to the payment type objects. Because of the Bridge pattern, any payment method can work with any gateway. |
| 224 | + |
| 225 | +**Output:** |
| 226 | +```bash |
| 227 | +Payment via CreditCard |
| 228 | +Processing the Payment For Amount=5000.0 Via RazorPay |
| 229 | + |
| 230 | +Payment via UPI |
| 231 | +Processing the Payment For Amount=1500.0 Via PayPal |
| 232 | + |
| 233 | +Payment via Wallet |
| 234 | +Processing the Payment For Amount=3400.0 Via Stripe |
| 235 | +``` |
| 236 | +--- |
| 237 | +## Real world Example |
| 238 | + |
| 239 | +A good real‑world example of the Bridge pattern can be seen in **JDBC (Java Database Connectivity)**. In JDBC, the application code interacts with high‑level abstractions such as `Connection`, `Statement`, and `DriverManager`. These classes do not depend on a specific database implementation. |
| 240 | + |
| 241 | +The actual implementations are provided by database drivers such as: |
| 242 | +- MySQL Driver |
| 243 | +- PostgreSQL Driver |
| 244 | +- Oracle Driver |
| 245 | + |
| 246 | +Because of this separation, the same application code can work with different databases simply by changing the JDBC driver. This is conceptually similar to the Bridge pattern where the abstraction (JDBC API) is separated from the implementation (database drivers). |
| 247 | + |
| 248 | +--- |
| 249 | +## Design Principles: |
| 250 | + |
| 251 | +- **Encapsulate What Varies** - Identify the parts of the code that are going to change and encapsulate them into separate class just like the Strategy Pattern. |
| 252 | +- **Favor Composition Over Inheritance** - Instead of using inheritance on extending functionality, rather use composition by delegating behavior to other objects. |
| 253 | +- **Program to Interface not Implementations** - Write code that depends on Abstractions or Interfaces rather than Concrete Classes. |
| 254 | +- **Strive for Loosely coupled design between objects that interact** - When implementing a class, avoid tightly coupled classes. Instead, use loosely coupled objects by leveraging abstractions and interfaces. This approach ensures that the class does not heavily depend on other classes. |
| 255 | +- **Classes Should be Open for Extension But closed for Modification** - Design your classes so you can extend their behavior without altering their existing, stable code. |
| 256 | +- **Depend on Abstractions, Do not depend on concrete class** - Rely on interfaces or abstract types instead of concrete classes so you can swap implementations without altering client code. |
| 257 | +- **Talk Only To Your Friends** - An object may only call methods on itself, its direct components, parameters passed in, or objects it creates. |
| 258 | +- **Don't call us, we'll call you** - This means the framework controls the flow of execution, not the user’s code (Inversion of Control). |
| 259 | +- **A class should have only one reason to change** - This emphasizes the Single Responsibility Principle, ensuring each class focuses on just one functionality. |
0 commit comments