Bridge pattern

From Wikipedia, the free encyclopedia

Jump to: navigation, search
Bridge in LePUS3 (legend)

The bridge pattern is a design pattern used in software engineering which is meant to "decouple an abstraction from its implementation so that the two can vary independently" [1]. The bridge uses encapsulation, aggregation, and can use inheritance to separate responsibilities into different classes.

When a class varies often, the features of object-oriented programming become very useful because changes to a program's code can be made easily with minimal prior knowledge about the program. The bridge pattern is useful when both the class as well as what it does varies. The class itself can be thought of as the implementation and what the class can do as the abstraction.

Variant: The implementation can be decoupled even more by deferring the presence of the implementation to the point where the abstraction is utilized.

Contents

[edit] Examples

[edit] Shape abstraction

When the abstraction and implementation are separated, they can vary independently. Consider the abstraction of shapes. There are many types of shapes, each with its own properties. And there are things that all shapes do. One thing all shapes can do is draw themselves. However, drawing graphics to a screen can sometimes be dependent on different graphics implementations or operating systems. Shapes have to be able to be drawn on many types of operating systems. Having the shape itself implement them all, or modifying the shape class to work with different architectures is not practical. The bridge helps by allowing the creation of new implementation classes that provide the drawing implementation. The abstraction class, shape, provides methods for getting the size or properties of a shape. The implementation class, drawing, provides an interface for drawing graphics. If a new shape needs to be created or there is a new graphics API to be drawn on, then it is very easy to add a new implementation class that implements the needed features.[2]

[edit] Structure

Abstraction
defines the abstract interface
maintains the Implementor reference
Refined Abstraction
extends the interface defined by Abstraction
Implementor
defines the interface for implementation classes
ConcreteImplementor
implements the Implementor interface


[edit] Code examples

[edit] Java

The following Java (SE 6) program illustrates the 'shape' example given above and will output:

API1.circle at 1.000000:2.000000 radius 7.500000
API2.circle at 5.000000:7.000000 radius 27.500000
/** "Implementor" */
interface DrawingAPI {
    public void drawCircle(double x, double y, double radius);
}
 
/** "ConcreteImplementor" 1/2 */
class DrawingAPI1 implements DrawingAPI {
   public void drawCircle(double x, double y, double radius) {
        System.out.printf("API1.circle at %f:%f radius %f\n", x, y, radius);
   }
}
 
/** "ConcreteImplementor" 2/2 */
class DrawingAPI2 implements DrawingAPI {
   public void drawCircle(double x, double y, double radius) { 
        System.out.printf("API2.circle at %f:%f radius %f\n", x, y, radius);
   }
}
 
/** "Abstraction" */
interface Shape {
   public void draw();                                            // low-level
   public void resizeByPercentage(double pct);     // high-level
}
 
/** "Refined Abstraction" */
class CircleShape implements Shape {
   private double x, y, radius;
   private DrawingAPI drawingAPI;
   public CircleShape(double x, double y, double radius, DrawingAPI drawingAPI) {
       this.x = x;  this.y = y;  this.radius = radius; 
       this.drawingAPI = drawingAPI;
   }
 
   // low-level i.e. Implementation specific
   public void draw() {
        drawingAPI.drawCircle(x, y, radius);
   }   
   // high-level i.e. Abstraction specific
   public void resizeByPercentage(double pct) {
        radius *= pct;
   }
}
 
/** "Client" */
class BridgePattern {
   public static void main(String[] args) {
       Shape[] shapes = new Shape[2];
       shapes[0] = new CircleShape(1, 2, 3, new DrawingAPI1());
       shapes[1] = new CircleShape(5, 7, 11, new DrawingAPI2());
 
       for (Shape shape : shapes) {
           shape.resizeByPercentage(2.5);
           shape.draw();
       }
   }
}

[edit] C#

The following C# program illustrates the "shape" example given above and will output:

API1.circle at 1:2 radius 7.5
API2.circle at 5:7 radius 27.5
 using System;
 
 /** "Implementor" */
 interface IDrawingAPI {
    void DrawCircle(double x, double y, double radius);
 }
 
 /** "ConcreteImplementor" 1/2 */
 class DrawingAPI1 : IDrawingAPI {
    public void DrawCircle(double x, double y, double radius) 
    {
        System.Console.WriteLine("API1.circle at {0}:{1} radius {2}", x, y, radius); 
    }
 }
 
 /** "ConcreteImplementor" 2/2 */
 class DrawingAPI2 : IDrawingAPI 
 {
    public void DrawCircle(double x, double y, double radius) 
    { 
        System.Console.WriteLine("API2.circle at {0}:{1} radius {2}", x, y, radius); 
    }
 }
 
 /** "Abstraction" */
 interface IShape {
    void Draw();                             // low-level (i.e. Implementation-specific)
    void ResizeByPercentage(double pct);     // high-level (i.e. Abstraction-specific)
 }
 
 /** "Refined Abstraction" */
 class CircleShape : IShape {
    private double x, y, radius;
    private IDrawingAPI drawingAPI;
    public CircleShape(double x, double y, double radius, IDrawingAPI drawingAPI) 
    {
        this.x = x;  this.y = y;  this.radius = radius; 
        this.drawingAPI = drawingAPI;
    }
    // low-level (i.e. Implementation-specific)
    public void Draw() { drawingAPI.DrawCircle(x, y, radius); }
    // high-level (i.e. Abstraction-specific)
    public void ResizeByPercentage(double pct) { radius *= pct; }
 }
 
 /** "Client" */
 class BridgePattern {
    public static void Main(string[] args) {
        IShape[] shapes = new IShape[2];
        shapes[0] = new CircleShape(1, 2, 3, new DrawingAPI1());
        shapes[1] = new CircleShape(5, 7, 11, new DrawingAPI2());
 
        foreach (IShape shape in shapes) {
            shape.ResizeByPercentage(2.5);
            shape.Draw();
        }
    }
 }

[edit] C# using generics

The following C# program illustrates the "shape" example given above and will output:

API1.circle at 1:2 radius 7.5
API2.circle at 5:7 radius 27.5
 using System;
 
 /** "Implementor" */
 interface IDrawingAPI {
    void DrawCircle(double x, double y, double radius);
 }
 
 /** "ConcreteImplementor" 1/2 */
 struct DrawingAPI1 : IDrawingAPI {
    public void DrawCircle(double x, double y, double radius) 
    {
        System.Console.WriteLine("API1.circle at {0}:{1} radius {2}", x, y, radius); 
    }
 }
 
 /** "ConcreteImplementor" 2/2 */
 struct DrawingAPI2 : IDrawingAPI 
 {
    public void DrawCircle(double x, double y, double radius) 
    { 
        System.Console.WriteLine("API2.circle at {0}:{1} radius {2}", x, y, radius); 
    }
 }
 
 /** "Abstraction" */
 interface IShape {
    void Draw();                             // low-level (i.e. Implementation-specific)
    void ResizeByPercentage(double pct);     // high-level (i.e. Abstraction-specific)
 }
 
 /** "Refined Abstraction" */
 class CircleShape<T> : IShape
    where T : struct, IDrawingAPI
 {
    private double x, y, radius;
    private IDrawingAPI drawingAPI = new T();
    public CircleShape(double x, double y, double radius) 
    {
        this.x = x;  this.y = y;  this.radius = radius;
    }
    // low-level (i.e. Implementation-specific)
    public void Draw() { drawingAPI.DrawCircle(x, y, radius); }
    // high-level (i.e. Abstraction-specific)
    public void ResizeByPercentage(double pct) { radius *= pct; }
 }
 
 /** "Client" */
 class BridgePattern {
    public static void Main(string[] args) {
        IShape[] shapes = new IShape[2];
        shapes[0] = new CircleShape<DrawingAPI1>(1, 2, 3);
        shapes[1] = new CircleShape<DrawingAPI2>(5, 7, 11);
 
        foreach (IShape shape in shapes) {
            shape.ResizeByPercentage(2.5);
            shape.Draw();
        }
    }
 }

[edit] C++

The following C++ program illustrates the "shape" example given above and will output:

API1.circle at 1:2 7.5
API2.circle at 5:7 27.5
#include <iostream>
 
using namespace std;
 
/* Implementor*/
class DrawingAPI {
  public:
   virtual void drawCircle(double x, double y, double radius) = 0;
   virtual ~DrawingAPI() {}
};
 
/* Concrete ImplementorA*/
class DrawingAPI1 : public DrawingAPI {
  public:
   void drawCircle(double x, double y, double radius) {
      cout << "API1.circle at " << x << ':' << y << ' ' << radius << endl;
   }
};
 
/* Concrete ImplementorB*/
class DrawingAPI2 : public DrawingAPI {
public:
   void drawCircle(double x, double y, double radius) {
      cout << "API2.circle at " << x << ':' << y << ' ' <<  radius << endl;
   }
};
 
/* Abstraction*/
class Shape {
  public:
   virtual ~Shape() {}
   virtual void draw() = 0;
   virtual void resizeByPercentage(double pct) = 0;
};
 
/* Refined Abstraction*/
class CircleShape : public Shape {
  public:
   CircleShape(double x, double y,double radius, DrawingAPI *drawingAPI) :
	   m_x(x), m_y(y), m_radius(radius), m_drawingAPI(drawingAPI)
   {}
   void draw() {
      m_drawingAPI->drawCircle(m_x, m_y, m_radius);
   }
   void resizeByPercentage(double pct) {
      m_radius *= pct;
   }
  private:
   double m_x, m_y, m_radius;
   DrawingAPI *m_drawingAPI;
};
 
int main(void) {
   CircleShape circle1(1,2,3,new DrawingAPI1());
   CircleShape circle2(5,7,11,new DrawingAPI2());
   circle1.resizeByPercentage(2.5);
   circle2.resizeByPercentage(2.5);
   circle1.draw();
   circle2.draw();
   return 0;
}

[edit] Python

The following Python program illustrates the "shape" example given above and will output:

API1.circle at 1:2 7.5
API2.circle at 5:7 27.5
# Implementor
class DrawingAPI:
	def drawCircle(x, y, radius):
		pass
 
# ConcreteImplementor 1/2
class DrawingAPI1(DrawingAPI):
	def drawCircle(self, x, y, radius):
		print "API1.circle at %f:%f radius %f" % (x, y, radius)
 
# ConcreteImplementor 2/2
class DrawingAPI2(DrawingAPI):
	def drawCircle(self, x, y, radius):
		print "API2.circle at %f:%f radius %f" % (x, y, radius)
 
# Abstraction
class Shape:
	# low-level
	def draw(self):
		pass
 
	# high-level
	def resizeByPercentage(self, pct):
		pass
 
# Refined Abstraction
class CircleShape(Shape):
	def __init__(self, x, y, radius, drawingAPI):
		self.__x = x
		self.__y = y
		self.__radius = radius
		self.__drawingAPI = drawingAPI
 
	# low-level i.e. Implementation specific
	def draw(self):
		self.__drawingAPI.drawCircle(self.__x, self.__y, self.__radius)
 
	# high-level i.e. Abstraction specific
	def resizeByPercentage(self, pct):
		self.__radius *= pct
 
def main():
	shapes = [
		CircleShape(1, 2, 3, DrawingAPI1()),
		CircleShape(5, 7, 11, DrawingAPI2())
	]
 
	for shape in shapes:
		shape.resizeByPercentage(2.5)
		shape.draw()
 
if __name__ == "__main__":
	main()

[edit] See also

[edit] References

  1. ^ Gamma, E, Helm, R, Johnson, R, Vlissides, J: Design Patterns, page 151. Addison-Wesley, 1995
  2. ^ Shalloway; Trott. Design Patterns Explained: A New Perspective on Object-Oriented Design---. 

[edit] External links

Personal tools