Two Interfaces
The intent of the Bridge pattern is to decouple an abstraction from its implementation so that the two can vary independently. (GoF 151) If you don’t think about that much, it sounds like a good idea to keep an application from grinding its gears when a change is made in either the abstraction or implementation. The Freemans (Head First Design Patterns, pp. 612-613) have a great example—a universal remote control. The remote control is the abstraction and a TV set is the implementor. Concrete implementors are the different brands of TVs. As new technology arises, the remote control can be updated with new gizmos. Likewise, the TV sets can also be updated and different brands will have their own unique features. A good Bridge design will allow each to be changed without breaking the other. So far so good.
An Abstraction Has-A Implementor
About six years ago, I started looking at different Bridge design pattern examples. I ran into examples that were examples of something but did not seem to be Bridge patterns. (One was nothing more than a single interface with two different implementations. The coder explained, See, that’s a bridge. I sat there with question marks floating above my head like some cartoon character.) The GoF intent statement and Freeman example were quite clear. However, the Abstraction interface and the Implementor interface, either of which could be an abstract class or interface structure, were bridged by the abstraction having-a implementor. To fully understand a Bridge pattern, you need to understand the relationship known as a bridge between the Abstraction and Implementor participants. First, though, see what the results are by pressing the Play button and Download the files:
For an overview, take a look at Figure 1. The top half is the structure laid out by The Gang of Four—the generic class diagram for a Bridge pattern. The bottom half is the PHP implementation that addresses a common issue: Variation in the content of a Web page and the structure of a Web page. By having two interfaces, either can change independently of the other. The example shows a Web page with variable content that is displayed in desktop and mobile devices.

Figure 1: Bridge Class diagrams
One of the important features of the Bridge pattern turns out to be quite subtle and easily overlooked.
The key method (Operation()) in the Abstraction participant is a concrete one.
In the example for this post, the IPage abstract class includes the buildPage() method. The buildPage() method uses a concrete implementation of the Implementor participant, (IDevice). You can see how the method is implemented in the IPage abstract class:
abstract class IPage
{
//Low-level
abstract function doDevice(IDevice $deviceNow);
//High-level
protected function buildPage()
{
echo $this->deviceSelected->buildDevice($this->header,$this->graphic,$this->body);
}
//Properties
protected $header, $graphic, $body, $deviceSelected;
}
?>
|
As you can see, the abstract function doDevice() expects an IDevice object as a parameter. The $deviceSelected property is one that will be assigned a concrete Implementor (IDevice). So, in the sense that both an abstract reference using code hinting and a concrete use of an implemented IDevice are part of the IPage abstract class, it can be said to “have a” Implementor (IDevice). (Click below to see the rest of the Bridge pattern.)
A Refined Abstraction
Nowhere else in the GoF book is there mention of a refined abstraction outside of the Bridge pattern. Generally, once an interface has abstracted methods, the job of those classes that implement the interface is to provide concrete operations. However, the refined abstraction extends the interface defined by the Abstraction (GoF, 154). So a refined abstraction is just an extension of another Interface (or Abstract class). Therein lies the final answer to the question about the implied aggregation. As you saw in the previous section, the Bridge design pattern is named after the bridge held up by aggregation between the Abstraction interface and the Implementor interface. However, we may not see that aggregation until the abstraction is refined in implementation by another class. The concrete implementation is done by the implementation of the Implementor class. In this example, the StandardPage class is the RefinedAbstraction.
class StandardPage extends IPage
{
public function doDevice(IDevice $deviceNow)
{
$this->deviceSelected=$deviceNow;
$this->setPage();
$this->buildPage();
}
/*The setPage() method could be part of the client, but then
the deDevice() method would require additional parameters. */
private function setPage()
{
$this->header="Future Bridge";
$this->graphic="airbridge.gif";
$this->body="Hop on, and we'll be over this bridge in no time!";
}
}
?>
|
At this point, the arrangement of the pattern clears up. The abstraction is separated from the implementation by refining the abstraction rather than implementing it by providing a concrete class. The implementation interface is implemented with concrete classes. However, the abstract class is the entry way for the client, which has-a implementation.
The setPage() method is relatively concrete for a refined abstraction, but I included it to cut down on parameters for the client to fill in. An alternative implementation would be to add more parameters to the doDevice() method and let the client take care of the concrete content.
Orthogonal Design
In the roughest sense, orthogonal refers to two (or more) elements that can vary independently of one another. For example, a Bridge may the Abstraction take care of the shape of an object and the Implementor the color. In that sense shape and color are orthogonal. Either could change and have no effect on the other.
In searching for a better characterization of orthogonal design, I came across an article, Design Pattern Orthogonal Component, that provides an example used with a state machine. In the state machine, the alarm clock is divided into two orthogonal regions: timekeeping and alarm. According to the article, dividing the state machine into two orthogonal regions is considered fairly expensive because each region requires a separate state-variable and extra work in dispatching events (e.g., ringing an alarm.)
As an alternative to orthogonal regions, the article suggests orthogonal components. In order to connect up the alarm with the alarm clock the article shows how to use aggregation to accomplish that linkage. It points out,
Concurrency virtually always arises within objects by aggregation; that is, multiple states of the components can contribute to a single state of the composite object.
Figure 2 shows how the page and device that formats the page are linked through aggregation. As such, the “bridge” in the Bridge design pattern is an orthogonal component. Because the IPage and IDevice are in an aggregate relationship, their life spans are identical. However, that does not mean that they cannot vary independently. Instead, it means that each can change independently without disrupting the other. At the same time the change will be reflected in the orthogonal relationship. For example, the structure (IDevice) of a Web page can change from desktop to smartphone, and the content (IPage) from C# to PHP without disrupting either and yet affecting both. The desktop page that used to discuss C# is now configured to display on iPhones and Androids and show a PHP discussion.

Figure 2: Orthogonal component in Bridge
The Implementators
Now that the concept of the bridge is established, the “other end” of the bridge from the Abstractor is the Implementator, which in this example is IDesign interface. The interface itself is a single method:
interface IDevice
{
function buildDevice($head,$image,$text);
}
?>
|
The three parameters reflect the three properties in IPage. If that seems to be a restrictively tight bind, instead of having three properties as parameters, you could use a single array. That would be more flexible, but a little messier as an initial example of the Bridge design pattern. All that’s left is the implementation of the concrete implementors:
//Desktop class Desktop implements IDevice { private $page; private $header; private $graphic; private $bodyText; public $pageNow; function buildDevice($head,$image,$text) { $this->header=$head; $this->graphic=$image; $this->bodyText=$text; //Begin heredoc string $this->pageNow=<< |