tl  tr
  Home | Tutorials | Articles | Videos | Products | Tools | Search
Interviews | Open Source | Tag Cloud | Follow Us | Bookmark | Contact   
 Design Patterns > Java Design Patterns > Bridge

Bridge 

Bridge pattern comes under Structural design pattern. Decouple an abstraction from its implementation so that the two can vary independently.

Behaviour & Advantages

  • Avoids permanent binding between an abstraction and an implementation.
  • Abstraction and implementation can vary independently.
  • Cleaner and loosely coupled client code.
Participants
  • Abstraction
    Defines an abstract interface and holds a reference to Implementor. It may be an interface or abstract class depending on the context.
  • Refined Abstraction
    An extension or implementation of Abstraction.
  • Implementor
    Defines an abstract interface for implementation classes. Abstraction uses Implementor to perform some operation.
  • Concrete Implementor
    An implementation of Implementor interface.

This example shows a simple payment system where user likes to pay his bills using various payment methods.

Here IBill acts as Abstraction and IPayment acts as Implementor. Classes PhoneBill, NewPhoneBill and WaterBill are Refined Abstractions. The payment methods such as CreditCardPayment and DebitCardPayment are Concrete Implementors.

We can observe that each Abstraction (PhoneBill, NewPhoneBill and WaterBill) has a reference to an Implementor (either CreditCardPayment or DebitCardPayment). The bill abstraction interface is shown below,

File Name  :  
com/bethecoder/tutorials/dp/bridge/IBill.java 
   
package com.bethecoder.tutorials.dp.bridge;

public interface IBill {
  
  /**
   * Pay the bill.
   */
  public void pay();
}
   

PhoneBill Refined Abstraction.

File Name  :  
com/bethecoder/tutorials/dp/bridge/PhoneBill.java 
   
package com.bethecoder.tutorials.dp.bridge;

public class PhoneBill implements IBill {

  private IPayment payment;
  private int billAmount;
  
  public PhoneBill(int billAmount, IPayment payment) {
    setBillAmount(billAmount);
    setPayment(payment);
  }
  
  @Override
  public void pay() {
    payment.pay(billAmount, "Phone Bill");
  }

  public void setPayment(IPayment payment) {
    this.payment = payment;
  }

  public int getBillAmount() {
    return billAmount;
  }

  public void setBillAmount(int billAmount) {
    this.billAmount = billAmount;
  }

  public IPayment getPayment() {
    return payment;
  }

}
   

NewPhoneBill Refined Abstraction.

File Name  :  
com/bethecoder/tutorials/dp/bridge/NewPhoneBill.java 
   
package com.bethecoder.tutorials.dp.bridge;

public class NewPhoneBill extends PhoneBill {

  public NewPhoneBill(int billAmount, int taxPercent, IPayment payment) {
    super(billAmount, payment);
    
    //Compute the tax and charge more
    billAmount = (int) (billAmount * (100.0+taxPercent)/100);
    setBillAmount(billAmount);
  }

  public void pay() {
    getPayment().pay(getBillAmount()"New Phone Bill");
  }
}
   

WaterBill Refined Abstraction.

File Name  :  
com/bethecoder/tutorials/dp/bridge/WaterBill.java 
   
package com.bethecoder.tutorials.dp.bridge;

public class WaterBill implements IBill {

  private IPayment payment;
  private int billAmount;
  
  public WaterBill(IPayment payment) {
    //Assume fixed water bill
    setBillAmount(250);
    setPayment(payment);
  }
  
  @Override
  public void pay() {
    payment.pay(billAmount, "Water Bill");
  }

  public void setPayment(IPayment payment) {
    this.payment = payment;
  }

  public int getBillAmount() {
    return billAmount;
  }

  public void setBillAmount(int billAmount) {
    this.billAmount = billAmount;
  }

  public IPayment getPayment() {
    return payment;
  }

}
   

Payment Implementor interface is shown below,

File Name  :  
com/bethecoder/tutorials/dp/bridge/IPayment.java 
   
package com.bethecoder.tutorials.dp.bridge;

public interface IPayment {

  /**
   * Pay the specified amount. 
   */
  public void pay(int amount, String reason);
  
}
   

CreditCardPayment Concrete Implementors.

File Name  :  
com/bethecoder/tutorials/dp/bridge/CreditCardPayment.java 
   
package com.bethecoder.tutorials.dp.bridge;

public class CreditCardPayment implements IPayment {

  @Override
  public void pay(int amount, String reason) {
    System.out.println("Paid Rs." + amount + " with credit card for '" + reason + "'");
  }

}
   

DebitCardPayment Concrete Implementors.

File Name  :  
com/bethecoder/tutorials/dp/bridge/DebitCardPayment.java 
   
package com.bethecoder.tutorials.dp.bridge;

public class DebitCardPayment implements IPayment {

  @Override
  public void pay(int amount, String reason) {
    System.out.println("Paid Rs." + amount + " with debit card for '" + reason + "'");
  }

}
   

Bridge pattern usage is shown below,

File Name  :  
com/bethecoder/tutorials/dp/bridge/Test.java 
   
package com.bethecoder.tutorials.dp.bridge;

public class Test {

  /**
   @param args
   */
  public static void main(String[] args) {

    IBill [] bills = new IBill[] {
        new PhoneBill(2000new DebitCardPayment()),
        new PhoneBill(40000new CreditCardPayment()),
        
        new NewPhoneBill(200010new DebitCardPayment()),
        new NewPhoneBill(4000020new CreditCardPayment()),
        
        new WaterBill(new DebitCardPayment()),
        new WaterBill(new CreditCardPayment())
    };
    
    for (IBill bill : bills) {
      bill.pay();
    }
  }

}
   

It gives the following output,
Paid Rs.2000 with debit card for 'Phone Bill'
Paid Rs.40000 with credit card for 'Phone Bill'

Paid Rs.2200 with debit card for 'New Phone Bill'
Paid Rs.48000 with credit card for 'New Phone Bill'

Paid Rs.250 with debit card for 'Water Bill'
Paid Rs.250 with credit card for 'Water Bill'



 
  


  
bl  br