Bridge Pattern is a structural design pattern which can be used to vary not only your implementations, but also your abstractions.
Lets jump into an example to understand this pattern.
Lets say we want to apply some algorithm to raw data of a speed metric that we receive from the ems based on the vendor device type reporting the metric . We currently have three vendors huw,cisco and brocade. We also have to apply algorithm based on the frequency range called as group size and currently we have group1,group2 and group3.
You expect that the algorithm will be refined many times as usability data is collected on the group size calculation. So your dilemma is that the group size algorithm is going to evolve and the vendor calculation algorithm is also going to evolve. Just abstracting the vendor calibration algorithm will not help as we are also going to need to vary the group size abstraction because it is going to change over time as the group size algorithm will be improved based on the user feedback.
We can consider using the Bridge Pattern here which will allow us to vary the implementation and the abstraction by placing the two in separate class hierarchies.Below is the class hierarchy we are going to build.
As we can see in the above diagram now we have two hierarchies, one for the group size and a separate one for vendor specific implementations. The bridge allows you to vary either side of the two hierarchies independently.By using this pattern we can decouples an implementation so that it is not bound permanently to an interface. Abstraction and implementation can be extended independently and changes to the concrete abstraction classes will not affect the client.
Lets code the example
Lets code the VendorCalibration implementation hierarchy first
public abstract class VendorCalibration { public abstract double calibrate(Double rawdata); }
public class HuwCalibration extends VendorCalibration { @Override public double calibrate(Double rawdata) { // TODO Auto-generated method stub return rawdata * 0.945; } }
public class BrocadeCalibration extends VendorCalibration { @Override public double calibrate(Double rawdata) { // TODO Auto-generated method stub return rawdata * 0.967; } }
public class CiscoCalibration extends VendorCalibration { @Override public double calibrate(Double rawdata) { // TODO Auto-generated method stub return rawdata * 0.8567; } }
lets code the group abstraction hierarchy
public abstract class GroupCalibration { public abstract double applyCorrection(Double rawdata); }
public class Group1 extends GroupCalibration { private VendorCalibration vendorCalibration; public Group1(VendorCalibration vendorCalibration) { super(); this.vendorCalibration = vendorCalibration; } public VendorCalibration getVendorCalibration() { return vendorCalibration; } public void setVendorCalibration(VendorCalibration vendorCalibration) { this.vendorCalibration = vendorCalibration; } @Override public double applyCorrection(Double rawdata) { // TODO Auto-generated method stub Double groupCalibrated = rawdata * 0.9889 + 0.0345; return vendorCalibration.calibrate(groupCalibrated); } }
public class Group2 extends GroupCalibration { private VendorCalibration vendorCalibration; public Group2(VendorCalibration vendorCalibration) { super(); this.vendorCalibration = vendorCalibration; } public VendorCalibration getVendorCalibration() { return vendorCalibration; } public void setVendorCalibration(VendorCalibration vendorCalibration) { this.vendorCalibration = vendorCalibration; } @Override public double applyCorrection(Double rawdata) { // TODO Auto-generated method stub Double groupCalibrated = rawdata * 0.9289 + 0.0445; return vendorCalibration.calibrate(groupCalibrated); } }
public class Group3 extends GroupCalibration { private VendorCalibration vendorCalibration; public Group3(VendorCalibration vendorCalibration) { super(); this.vendorCalibration = vendorCalibration; } public VendorCalibration getVendorCalibration() { return vendorCalibration; } public void setVendorCalibration(VendorCalibration vendorCalibration) { this.vendorCalibration = vendorCalibration; } @Override public double applyCorrection(Double rawdata) { // TODO Auto-generated method stub Double groupCalibrated = rawdata * 0.8889 + 0.0645; return vendorCalibration.calibrate(groupCalibrated); } }
Lets code the driver class
public class Test { public static void main(String[] args) { Double rawdata=34.56565; GroupCalibration groupX = new Group1(new HuwCalibration()); System.out.println(groupX.applyCorrection(rawdata)); GroupCalibration groupY = new Group1(new BrocadeCalibration()); System.out.println(groupY.applyCorrection(rawdata)); GroupCalibration groupV = new Group2(new HuwCalibration()); System.out.println(groupV.applyCorrection(rawdata)); GroupCalibration groupZ = new Group3(new BrocadeCalibration()); System.out.println(groupZ.applyCorrection(rawdata)); } }