The Bridge pattern is a structural design pattern that decouples an abstraction from its implementation, allowing them to vary independently. It provides a way to handle complex class hierarchies by separating them into two separate hierarchies: the abstraction hierarchy and the implementation hierarchy. This pattern promotes loose coupling and flexibility in designing and evolving systems. In PHP, the Bridge pattern can be implemented using interfaces and classes that implement those interfaces.
Example implementation in PHP:
// Abstraction interface that defines the abstraction methods.
interface Shape {
public function draw();
}
// Concrete implementation classes that implement the abstraction interface.
class Circle implements Shape {
private $radius;
private $color;
public function __construct($radius, $color) {
$this->radius = $radius;
$this->color = $color;
}
public function draw() {
echo "Drawing a circle with radius " . $this->radius . " and color " . $this->color . ".<br>";
}
}
class Rectangle implements Shape {
private $width;
private $height;
private $color;
public function __construct($width, $height, $color) {
$this->width = $width;
$this->height = $height;
$this->color = $color;
}
public function draw() {
echo "Drawing a rectangle with width " . $this->width . ", height " . $this->height . ", and color " . $this->color . ".<br>";
}
}
// Implementor interface that defines the implementation methods.
interface DrawingAPI {
public function drawCircle($radius, $x, $y);
public function drawRectangle($width, $height, $x, $y);
}
// Concrete implementor classes that implement the implementor interface.
class DrawingAPI1 implements DrawingAPI {
public function drawCircle($radius, $x, $y) {
echo "API 1 - Drawing a circle with radius " . $radius . " at coordinates (" . $x . "," . $y . ").<br>";
}
public function drawRectangle($width, $height, $x, $y) {
echo "API 1 - Drawing a rectangle with width " . $width . ", height " . $height . " at coordinates (" . $x . "," . $y . ").<br>";
}
}
class DrawingAPI2 implements DrawingAPI {
public function drawCircle($radius, $x, $y) {
echo "API 2 - Drawing a circle with radius " . $radius . " at coordinates (" . $x . "," . $y . ").<br>";
}
public function drawRectangle($width, $height, $x, $y) {
echo "API 2 - Drawing a rectangle with width " . $width . ", height " . $height . " at coordinates (" . $x . "," . $y . ").<br>";
}
}
// Abstraction class that maintains a reference to the implementation class.
abstract class ShapeAbstraction {
protected $drawingAPI;
public function __construct(DrawingAPI $drawingAPI) {
$this->drawingAPI = $drawingAPI;
}
abstract public function draw();
}
// Refined abstraction classes that extend the abstraction class.
class CircleShape extends ShapeAbstraction {
private $x;
private $y;
private $radius;
public function __construct($x, $y, $radius, DrawingAPI $drawingAPI) {
parent::__construct($drawingAPI);
$this->x = $x;
$this->y = $y;
$this->radius = $radius;
}
public function draw() {
$this->drawingAPI->drawCircle($this->radius, $this->x, $this->y);
}
}
class RectangleShape extends ShapeAbstraction {
private $x;
private $y;
private $width;
private $height;
public function __construct($x, $y, $width, $height, DrawingAPI $drawingAPI) {
parent::__construct($drawingAPI);
$this->x = $x;
$this->y = $y;
$this->width = $width;
$this->height = $height;
}
public function draw() {
$this->drawingAPI->drawRectangle($this->width, $this->height, $this->x, $this->y);
}
}
// Usage example:
$drawingAPI1 = new DrawingAPI1();
$drawingAPI2 = new DrawingAPI2();
$circleShape1 = new CircleShape(1, 2, 3, $drawingAPI1);
$circleShape1->draw();
// Output: API 1 - Drawing a circle with radius 3 at coordinates (1,2).
$circleShape2 = new CircleShape(4, 5, 6, $drawingAPI2);
$circleShape2->draw();
// Output: API 2 - Drawing a circle with radius 6 at coordinates (4,5).
$rectangleShape1 = new RectangleShape(1, 2, 3, 4, $drawingAPI1);
$rectangleShape1->draw();
// Output: API 1 - Drawing a rectangle with width 3, height 4 at coordinates (1,2).
$rectangleShape2 = new RectangleShape(5, 6, 7, 8, $drawingAPI2);
$rectangleShape2->draw();
// Output: API 2 - Drawing a rectangle with width 7, height 8 at coordinates (5,6).
We have the Shape
interface representing the abstraction hierarchy, which is implemented by the concrete shape classes (Circle
and Rectangle
). These concrete classes encapsulate the specific shape-related properties and behavior.
The DrawingAPI
interface represents the implementation hierarchy, which defines the methods for drawing circles and rectangles. The concrete classes DrawingAPI1
and DrawingAPI2
implement the DrawingAPI
interface and provide their own implementations of the drawing methods.
The ShapeAbstraction
class acts as the bridge between the abstraction and implementation. It maintains a reference to the DrawingAPI
object and provides an abstract draw()
method.
The refined abstraction classes (CircleShape
and RectangleShape
) extend the ShapeAbstraction
class and implement the draw()
method by delegating the drawing functionality to the corresponding method in the DrawingAPI
object.
In the usage example, we create instances of the concrete classes and specify the desired implementation (DrawingAPI1
or DrawingAPI2
) to be used by the bridge. Depending on the implementation passed, the corresponding drawing API's method is invoked, resulting in different drawing behavior.
The Bridge pattern allows for the separation of abstractions and implementations, enabling them to evolve independently. It promotes flexibility, extensibility, and easy swapping of implementations at runtime. It also avoids the problem of an exponential increase in classes when dealing with multiple variations of abstractions and implementations.