Bridge pattern separates an abstraction from its implementation, so that the two get loosely coupled and can vary independently.
In practice, the terms abstraction and implementation refer to objects. The abstraction object has a reference to the implementation object and delegates some responsibilities to it. Both of them can be implemented to their own interface, so their implementation can be changeable.
Bridge is a structural pattern.
This Java example is about televisions and remote controls. There are several televisions and several remote controls. It is desirable to combine any remote to any television. This is possible because televisions and remote controls are programmed to interfaces.
Every remote control has a reference to a television and delegates responsibilities to it. For example, when the on button is pressed on a remote, it delegates the request to the television and that turns on.
As is was mentioned, televisions have a common interface.
package com.programcodex.designpatterns.bridge;
public interface Television {
public void on();
public void off();
public void setChannel(int channel);
public int getChannel();
}
The first television is the OldWoodenTV
, which implements the Television
interface.
It's very simple.
package com.programcodex.designpatterns.bridge;
public class OldWoodenTV implements Television {
private int channel;
@Override
public void on() {
System.out.println("Old wooden television is on");
}
@Override
public void off() {
System.out.println("Old wooden television is off");
}
@Override
public void setChannel(int channel) {
this.channel = channel;
System.out.println("Channel: " + channel);
}
@Override
public int getChannel() {
return channel;
}
}
The second and last television implementation in this example is the ColorTV
,
which is a much more modern television like the first one.
This one has Bluetooth and can say farewell.
package com.programcodex.designpatterns.bridge;
public class ColorTV implements Television {
private int channel;
@Override
public void on() {
System.out.println("Color television is on");
connectToBluetoothSpeakers();
}
@Override
public void off() {
echoByeBye();
System.out.println("Color television is off");
}
@Override
public void setChannel(int channel) {
this.channel = channel;
System.out.println("Selected channel: " + channel);
}
@Override
public int getChannel() {
return channel;
}
private void connectToBluetoothSpeakers() {
System.out.println("Connected to Bluetooth speakers");
}
private void echoByeBye() {
System.out.println("Bye-bye");
}
}
Now come the remote controls. Their interface is defined below.
package com.programcodex.designpatterns.bridge;
public interface RemoteControl {
public void on();
public void off();
public void switchChannel(int channel);
public void setPrevChannel();
public void setNextChannel();
}
The UniversalRC
class implements the RemoteControl
interface.
It holds a reference to a Television
instance in a field and calls its methods.
The Television
type is an interface, so it can be OldWoodenTV
or ColorTV
.
package com.programcodex.designpatterns.bridge;
public class UniversalRC implements RemoteControl {
private Television television;
public UniversalRC(Television television) {
this.television = television;
}
@Override
public void on() {
television.on();
}
@Override
public void off() {
television.off();
}
@Override
public void switchChannel(int channel) {
television.setChannel(channel);
}
@Override
public void setPrevChannel() {
television.setChannel(television.getChannel() - 1);
}
@Override
public void setNextChannel() {
television.setChannel(television.getChannel() + 1);
}
}
The SimpleRC
class is another implementation of the RemoteControl
interface,
and also has a Television
instance reference,
but it is a little bit simpler than the previous remote.
It doesn’t support every operation of the interface, but it works.
package com.programcodex.designpatterns.bridge;
public class SimpleRC implements RemoteControl {
private Television television;
public SimpleRC(Television television) {
this.television = television;
}
@Override
public void on() {
television.on();
}
@Override
public void off() {
television.off();
}
@Override
public void switchChannel(int channel) {
television.setChannel(channel);
}
@Override
public void setPrevChannel() {
// not supported
}
@Override
public void setNextChannel() {
// not supported
}
}
And we are done. It’s time to run these things.
First, an OldWoodenTV
and a ColorTV
are instantiated.
After that, they are used by the UniversalRC
and the SimpleRC
classes.
The testRemore
method gets a remoteControl
as a parameter.
It presses the remote’s on button, switch channels and finally presses the off button.
package com.programcodex.designpatterns.bridge;
public class TestBridge {
public static void main(String[] args) {
Television owTv = new OldWoodenTV();
Television colorTv = new ColorTV();
System.out.println("Universal RC test:");
RemoteControl rc = new UniversalRC(owTv);
testRemore(rc);
rc = new UniversalRC(colorTv);
testRemore(rc);
System.out.println("\nSimple RC test:");
rc = new SimpleRC(owTv);
testRemore(rc);
rc = new SimpleRC(colorTv);
testRemore(rc);
}
private static void testRemore(RemoteControl remoteControl) {
System.out.println("");
remoteControl.on();
remoteControl.switchChannel(5);
remoteControl.setNextChannel();
remoteControl.setPrevChannel();
remoteControl.off();
}
}
The output of the above test class: