PHP: Bridge

Bridge is a structural design pattern that divides business logic or huge class into separate class hierarchies that can be developed independently.

One of these hierarchies (0often called the Abstraction) will get a reference to an object of the second hierarchy (Implementation). The abstraction will be able to delegate some (sometimes, most) of its calls to the implementations object. Since all implementations will have a common interface, they would be interchangeable inside the abstraction.

Application of the pattern in PHP

Complexity:

Popularity:

Usage examples: The Bridge pattern is especially useful when supporting multiple types of database servers or working with several API providers of a certain kind (for example, cloud platforms, social networks, etc.)

Example: Structure of the Pattern

This example illustrates the structure of the Bridge design pattern and focuses on following questions:

What classes does it consists of?

What roles do these classes play?

In what way the elements of the pattern are related?

After learning about the pattern's structure it will be easier for you to grasp the following example, based on a real world PHP use case.

BridgeStructural.php: Structural Example

<?php
namespace RefactoringGuru\Bridge\Structural;
/**
* The Abstraction defines the interface for the "control" part of the two class
* hierarchies. It maintains a reference to an object of the Implementation
* hierarchy and delegates all of the real work to this object.
*/
class Abstraction
{
/**
* @var Implementation
*/
protected $implementation;
public function __construct(Implementation $implementation)
{
$this->implementation = $implementation;
}
public function operation()
{
return "Abstraction: Base operation with:\n".
$this->implementation->operationImplementation();
}
}
/**
* You can extend the Abstraction without changing the Implementation classes.
*/
class ExtendedAbstraction extends Abstraction
{
public function operation()
{
return "ExtendedAbstraction: Extended operation with:\n".
$this->implementation->operationImplementation();
}
}
/**
* The Implementation defines the interface for all implementation classes. It
* doesn't have to match the Abstraction's interface. In fact, the two
* interfaces can be entirely different. Typically the Implementation interface
* provides only primitive operations, while the Abstraction defines higher-
* level operations based on those primitives.
*/
interface Implementation
{
public function operationImplementation();
}
/**
* Each Concrete Implementation corresponds to a specific platform and
* implements the Implementation interface using that platform's API.
*/
class ConcreteImplementationA implements Implementation
{
public function operationImplementation()
{
return "ConcreteImplementationA: Here's the result on the platform A.\n";
}
}
class ConcreteImplementationB implements Implementation
{
public function operationImplementation()
{
return "ConcreteImplementationB: Here's the result on the platform B.\n";
}
}
/**
* Except for the initialization phase, where an Abstraction object gets linked
* with a specific Implementation object, the client code should only depend on
* the Abstraction class. This way the client code can support any abstraction-
* implementation combination.
*/
function clientCode(Abstraction $abstraction)
{
// ...
print($abstraction->operation());
// ...
}
/**
* The client code should be able to work with any pre-configured abstraction-
* implementation combination.
*/
$implementation = new ConcreteImplementationA();
$abstraction = new Abstraction($implementation);
clientCode($abstraction);
print("\n");
$implementation = new ConcreteImplementationB();
$abstraction = new ExtendedAbstraction($implementation);
clientCode($abstraction);

Output.txt: Output

Abstraction: Base operation with:
ConcreteImplementationA: Here's the result on the platform A.
ExtendedAbstraction: Extended operation with:
ConcreteImplementationB: Here's the result on the platform B.

Example: Real World Example

In this example, the Page hierarchy acts as the Abstraction, and the Renderer hierarchy acts as the Implementation. Objects of the Page class can assemble web pages of a particular kind using basic elements provided by a Renderer object attached to that page. Since both of the class hierarchies are separate, you can add a new Renderer class without changing any of the Page classes and vice versa.