GoF Definition: Decouple an abstraction from its implementation so that the two can vary independently.
In this pattern, the abstract class is separated from the implementation class and we provide a bridge interface between them. This interface helps us to make concrete class functionalities independent from the interface implementer class. We can alter these different kind of classes structurally without affecting each other.
In a software product development company, the development team and technical support team both play a crucial role. A change in the operational strategy of one team should not have a direct impact on the other team. Here the technical support team plays the role of a bridge between the clients and the development team that implements the product.
This pattern is used in a GUI framework. It separates Window abstraction from Window implementation in Linux/Mac OSs. The following illustration is a classical example in the software development field.
Consider a situation like this:
We’ll use bridge pattern to decouple the interfaces in our example from the implementations. After our implementation it will have a cleaner look (follow our UML diagram).
High-level structure of the parts of the program is as follows:
Here we have implemented both an abstraction-specific and an implementer-specific method to represent the power and usefulness of this pattern. We can draw a triangle and a rectangle with a particular color with the implementer-specific method drawShape(). We can change the thickness of the border by the abstraction-specific method modifyBorder() . Please go through the code.
package bridge.pattern.demo;
//Colors-The Implementer
interface IColor
{
void fillWithColor(int border);
}
class RedColor implements IColor
{
@Override
public void fillWithColor(int border)
{
System.out.print("Red color with " +border+" inch border");
}
}
class GreenColor implements IColor
{
@Override
public void fillWithColor(int border)
{
System.out.print("Green color with " +border+" inch border.");
}
}
//Shapes-The Abstraction
abstract class Shape
{
//Composition
protected IColor color;
protected Shape(IColor c)
{
this.color = c;
}
abstract void drawShape(int border);
abstract void modifyBorder(int border,int increment);
}
class Triangle extends Shape
{
protected Triangle(IColor c)
{
super(c);
}
//Implementer-specific method
@Override
void drawShape(int border) {
System.out.print(" This Triangle is colored with: ");
color.fillWithColor(border);
}
//Abstraction-specific method
@Override
void modifyBorder(int border,int increment) {
System.out.println(" Now we are changing the border length "+increment+ " times");
border=border*increment;
drawShape(border);
}
}
class Rectangle extends Shape
{
public Rectangle(IColor c)
{
super(c);
}
//Implementer-specific method
@Override
void drawShape(int border)
{
System.out.print(" This Rectangle is colored with: ");
color.fillWithColor(border);
}
//Abstraction-specific method
@Override
void modifyBorder(int border,int increment) {
System.out.println(" Now we are changing the border length "+increment+ " times");
border=border*increment;
drawShape(border);
}
}
class BridgePatternEx
{
public static void main(String[] args)
{
System.out.println("*****BRIDGE PATTERN*****");
//Coloring Green to Triangle
System.out.println(" Coloring Triangle:");
IColor green = new GreenColor();
Shape triangleShape = new Triangle(green);
triangleShape.drawShape(20);
triangleShape.modifyBorder(20, 3);
//Coloring Red to Rectangle
System.out.println(" Coloring Rectangle :");
IColor red = new RedColor();
Shape rectangleShape = new Rectangle(red);
rectangleShape.drawShape(50);
//Modifying the border length twice
rectangleShape.modifyBorder(50,2);
}
}
We have repeatedly referred here to the two hierarchies: abstraction and implementer. An abstraction should be an abstract class.” Is the statement correct?
No. We can use either an abstract class or an interface. And the same rule applies for the implementer class also.
What are refined abstractions?
Children of an abstraction are termed “refined abstractions.”
Who are concrete implementers?
Children of an implementer.
How can you differentiate an abstraction from its implementer?
In general, an abstraction contains the reference to its implementer.
How can you change the implementers dynamically or at runtime?
By changing the reference in the abstraction.