Wikipedia:

bridge pattern

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" (Gamma et al.). 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 not only the class itself varies often but also what the class does. The class itself can be thought of as the abstraction and what the class can do as the implementation.

Variant: The implementation can be decoupled even more by deferring the presence of the implementation to the point where the abstraction is utilized (as illustrated by the Visual Prolog example below).

Non-technical examples

Shape abstraction

When the abstraction and implementation are separated they can vary independently. Consider an abstraction such as shapes. There are many types of shapes and each with its own properties but 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 systems, but 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 classes that provide the drawing implementation. The abstract - shape - class provides methods for getting the size or properties of a shape while the implementation - drawing - class provides an interface for drawing graphics. Now 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 class that implements the needed features.[1]

Car abstraction

Imagine two types of cars (the abstraction), a Jaguar and a Mercedes (both are Refinements of the Abstraction). The Abstraction defines that a Car has features such as tires and an engine. Refinements of the Abstraction declare what specific kind of tires and engine it has.
Finally, there are two types of road. The road is the Implementor (see image below). A highway and an interstate highway are the Implementation Details. Any car refinement needs to be able to drive on any type of road; this concept is what the Bridge Pattern is all about.

Structure

Image:Bridge classdia.png

Client
The Object using the bridge pattern
Abstraction
defines the abstract interface
maintains the implementor reference
Refined Abstraction
Extends the interface defined by Abstraction
Implementor
defines the interface for implementation classes. (Typically the Abstraction interface defines higher level operations based on this interface operations)
ConcreteImplementor
implements the Implementor interface

Code examples

Java

The following Java 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

<source lang="java"> import java.util.*; /** "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();
      }
  }

} </source>

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

<source lang="csharp">

using System;

/** "Implementor" */
interface DrawingAPI {
   void DrawCircle(double x, double y, double radius);
}

/** "ConcreteImplementor" 1/2 */
class DrawingAPI1 : DrawingAPI {
   public void DrawCircle(double x, double y, double radius) 
   {
       System.Console.WriteLine("API1.circle at {0}:{1} radius {2}\n", x, y, radius); 
   }
}

/** "ConcreteImplementor" 2/2 */
class DrawingAPI2 : DrawingAPI 
{
   public void DrawCircle(double x, double y, double radius) 
   { 
       System.Console.WriteLine("API2.circle at {0}:{1} radius {2}\n", x, y, radius); 
   }
}

/** "Abstraction" */
interface Shape {
   void Draw();                             // low-level
   void ResizeByPercentage(double pct);     // high-level
}

/** "Refined Abstraction" */
class CircleShape : 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());

       foreach (Shape shape in shapes) {
           shape.ResizeByPercentage(2.5);
           shape.Draw();
       }
   }
}

</source>

Perl

The following Perl 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

<source lang="perl">

      1. ConcreteImplementor 1/2

package DrawingAPI1;

sub new {

       my $class = shift;
       return bless({}, $class);

}

sub draw_circle {

       my($self, $x, $y, $radius) = @_;
       print("API1.circle at $x:$y radius $radius\n");

}

1;

      1. ConcreteImplementor 2/2

package DrawingAPI2;

sub new {

       my $class = shift;
       return bless({}, $class);

}

sub draw_circle {

       my($self, $x, $y, $radius) = @_;
       print("API2.circle at $x:$y radius $radius\n");

}

1;

      1. Refined Abstraction

package CircleShape;

sub new {

       my $class = shift;
       my ($x, $y, $radius, $drawing_api) = @_;
       my $self = bless({
               x => $x,
               y => $y,
               radius => $radius,
               drawing_api => $drawing_api,
       }, $class);
       return $self;

}

sub draw {

       my $self = shift;
       $self->{drawing_api}->draw_circle(
               $self->{x}, $self->{y}, $self->{radius});

}

sub resize_by_percentage {

       my($self, $percent) = @_;
       $self->{radius} *= $percent;

}

1;

      1. client

my @shapes = (

       CircleShape->new(1, 2, 3,  DrawingAPI1->new),
       CircleShape->new(5, 7, 11, DrawingAPI2->new),

);

foreach my $shape (@shapes) {

       $shape->resize_by_percentage(2.5);
       $shape->draw();

}

</source>

PHP

Note that this example uses features available only in PHP 5 and up. It will not work in PHP 4.

<source lang="php">

#!/usr/local/bin/php
<?php
/** "Implementor" */
interface DrawingAPI {
   public function drawCircle($x, $y, $radius);
}

/** "ConcreteImplementor" 1/2 */
class DrawingAPI1 implements DrawingAPI {
   public function drawCircle($x, $y, $radius) 
   { echo "API1.circle at $x:$y radius $radius\n"; }
}

/** "ConcreteImplementor" 2/2 */
class DrawingAPI2 implements DrawingAPI {
   public function drawCircle($x, $y, $radius) 
  { echo "API2.circle at $x:$y radius $radius\n"; }
}

/** "Abstraction" */
interface Shape {
   public function draw();                       // low-level
   public function resizeByPercentage($pct);     // high-level
}

/** "Refined Abstraction" */
class CircleShape implements Shape {
   private $x;
   private $y;
   private $radius;
   private $drawingAPI;
   public function __construct($x, $y, $radius, DrawingAPI $drawingAPI) {
       $this->x = $x;
       $this->y = $y;
       $this->radius = $radius; 
       $this->drawingAPI = $drawingAPI;
   }
   // low-level i.e. Implementation specific
   public function draw() { $this->drawingAPI->drawCircle($this->x, $this->y, $this->radius); }   
   // high-level i.e. Abstraction specific
   public function resizeByPercentage($pct) { $this->radius *= $pct; }
}

/** "Client" */
$shapes = array();
$shapes[] = new CircleShape(1, 2, 3, new DrawingAPI1());
$shapes[] = new CircleShape(5, 7, 11, new DrawingAPI2());

foreach ($shapes as $shape) {
  $shape->resizeByPercentage(2.5);
  $shape->draw();
}

</source>

Python

The following Python 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

<source lang="python"> class CircleShape:

   def __init__(self,x,y,r,da):
       self.x = x
       self.y = y
       self.r = r
       self.da = da
   def draw(self):
       self.da.drawCircle(self.x,self.y,self.r)
   def resizeByPercentage(self,pct):
       self.r *= pct

class DrawingAPI2:

   def drawCircle(self,x,y,r): 
       print "API2.circle at %f:%f radius %f" % (x,y,r)

class DrawingAPI1:

   def drawCircle(self,x,y,r): 
       print "API1.circle at %f:%f radius %f" % (x,y,r)

if __name__ == '__main__':

   shapes = [CircleShape(1,2,3,DrawingAPI1()), CircleShape(5,7,11,DrawingAPI2())]
   for shape in shapes:
       shape.resizeByPercentage(2.5)
       shape.draw()

</source>

Ruby

This will print:

API1.circle at 1.000000:2.000000 radius 7.500000
API2.circle at 5.000000:7.000000 radius 27.500000

<source lang="ruby"> class CircleShape

 def initialize(x, y, r, da)
   @x, @y, @r, @da = x, y, r, da
 end

 def draw
   @da.draw_circle(@x, @y, @r)
 end

 def resize_by_percentage(pct)
   @r *= pct
 end

end

class DrawingAPI1

 def draw_circle(x, y, r)
   printf "API1.circle at %f:%f radius %f\n", x, y, r
 end

end

class DrawingAPI2

 def draw_circle(x, y, r)
   printf "API2.circle at %f:%f radius %f\n", x, y, r
 end

end

shapes = [CircleShape.new(1, 2, 3, DrawingAPI1.new), CircleShape.new(5, 7, 11, DrawingAPI2.new)] shapes.each do |shape|

 shape.resize_by_percentage(2.5)
 shape.draw

end </source>

DrawingAPI1 and DrawingAPI2 can be implemented more elegantly as blocks.[citation needed]

Visual Prolog

This example illustrates the variant in which the presence of the implementation is deferred to the point where the model is used.

Abstract implementor

interface drawingApi
    predicates
        drawCircle : (real X, real Y, real Radius).
        drawSquare : (real X, real Y, real Width).
end interface drawingApi

Concrete implementor 1 (of 2)

class openGL : drawingApi
end class openGL

implement openGL
    clauses
        drawCircle(X, Y, Radius) :-
            stdio::writef("OpenGL circle at (%,%) with radius=%\n", X, Y, Radius).
    clauses
        drawSquare(X, Y, Width) :-
            stdio::writef("OpenGL square at (%,%) with width=%\n", X, Y, Width).
end implement openGL

Concrete implementor 2 (of 2)

class directX : drawingApi
end class directX

% directX (trivial) implementation skipped

Abstract shape data model

interface shape
    predicates
        draw : (drawingApi DrawingAPI).
end interface shape
class circle : shape
    constructors
        new : (real X, real Y, real Radius).
end class circle

implement circle
    facts
        x : real.
        y: real.
        radius : real.
    clauses
        new(X, Y, Radius) :-
            x := X,
            y := Y,
            radius := Radius.
    clauses
        draw(DrawingAPI) :-
            DrawingAPI:drawCircle(x, y, radius).
end implement circle
class square : shape
    constructors
        new : (real X, real Y, real Width).
end class square

implement square
    facts
        x : real.
        y: real.
        width : real.
    clauses
        new(X, Y, Width) :-
            x := X,
            y := Y,
            width := Width.
    clauses
        draw(DrawingAPI) :-
            DrawingAPI:drawSquare(x, y, width).
end implement square

Client code

goal
    console::init(),
    % The concrete model is a list of shapes
    ConcreteModel = [circle::new(1, 2, 7.5), circle::new(5, 7, 27.5), square::new(2.9, 80, 17)],
    % draw using OpenGL
    OpenGL = openGL::new(),
    foreach S1 = list::getMember_nd(ConcreteModel) do
        S1:draw(OpenGL)
    end foreach,
    % draw the same model using DirectX
    DirectX = directX::new(),
    foreach S2 = list::getMember_nd(ConcreteModel) do
        S2:draw(DirectX)
    end foreach.

[[C++ (programming language)|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

<source lang="cpp">

  1. include "stdafx.h"
  2. include <iostream>
  3. include <vector>
  4. include <algorithm>
  5. include <functional>

using namespace std;

/************************************************************************/ /* Implementor */ /************************************************************************/ // interface class DrawingAPI { public: virtual void drawCircle(double x, double y, double radius) = 0; };

//concrete implementor1 class DrawingAPI1 : public DrawingAPI { public: void drawCircle(double x, double y, double radius) { cout<<"API1.circle at"<<x<<":"<<y<<" "<< radius<<endl; } };

//concrete implementor2 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 void draw() = 0; virtual void resizeByPercentage(double pct) = 0; };

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; }; ////////////////////////////////////////////////////////////////////////// //Test typedef std::vector<Shape*>::iterator ShapeIt; int main(int argc, char* argv[]) { std::vector<Shape*> vecShapes; vecShapes.push_back(new CircleShape(1,2,3,*(new DrawingAPI1))); vecShapes.push_back(new CircleShape(5,7,11,*(new DrawingAPI2))); ShapeIt begin,end; begin = vecShapes.begin(); end = vecShapes.end(); for_each(begin,end,std::bind2nd(std::mem_fun(&Shape::resizeByPercentage),2.5)); for_each(begin,end,mem_fun(&Shape::draw)); return 0; } </source>

See also

External links

References

  1. ^ Shalloway; Trott. Design Patterns Explained: A New Perspective on Object-Oriented Design. 

 
 
 

Join the WikiAnswers Q&A community. Post a question or answer questions about "bridge pattern" at WikiAnswers.

 

Copyrights:

Wikipedia. This article is licensed under the GNU Free Documentation License. It uses material from the Wikipedia article "Bridge pattern" Read more

Search for answers directly from your browser with the FREE Answers.com Toolbar!  
Click here to download now. 

Get Answers your way! Check out all our free tools and products.

On this page:   E-mail   print Print  Link  

 

Keep Reading

Mentioned In: