Definition: The bridge pattern "decouples an abstraction from its implementation so that the two can vary independently". At least, that's the official definition. The bridge pattern actually couples one interface to another interface, thereby preventing any coupling between any implementations. The "implementation" being decoupled from the "abstraction" is actually an implementation of a different abstraction, making this pattern's definition confusing.
Usage: Use the bridge pattern to avoid coupling two concrete classes that are otherwise separate.
//this is the first abstraction being bridged
abstract class GameWindow {
abstract drawTo(Graphics2D g2d)
getRendererUtility() {return renderer;}
setRendererUtility(RendererUtility renderer) {this.renderer = renderer;}
RendererUtility renderer;
}
//this is the second abstraction being bridged
interface RendererUtility {
drawCircle(Graphics2D g2d, double radius, int xCenter, int yCenter)
drawImage(Graphics2D g2d, Image image, int x, int y)
drawText(Graphics2D g2d, String text, int x, int y)
}
//these class implement the first abstraction
class MainScreenWindow extends GameWindow {
drawTo(Graphics2D g2d) {
//draw the player
getRendererUtility().drawImage(g2d, playerImage, xPlayer, yPlayer);
//draw the sun
getRendererUtility().drawCircle(g2d, 15, 100, 0);
//draw some other sprites
}
BufferedImage playerImage = load the image for the player
int xPlayer, yPlayer //both set to some value
}
class MenuScreenWindow extends GameWindow {
drawTo(Graphics2D g2d) {
getRendererUtility().drawImage(g2d, menuScreenImage, 0, 0);
getRendererUtility().drawText(g2d, "My Menu", 100, 0);
//draw some buttons, etc.
}
BufferedImage menuScreenImage = load the image for the menu screen
}
//these classes implement the second abstraction
HardwareAccelleratedRendererUtility extends RendererUtility {
drawCircle(Graphics2D g2d, double radius, int xCenter, int yCenter) {
draw a circle using hardware acceleration
}
drawImage(Graphics2D g2d, Image image, int x, int y) {
draw an image using hardware acceleration
}
drawText(Graphics2D g2d, String text, int x, int y) {
draw text using hardware acceleration
}
}
SoftwareOnlyRendererUtility extends RendererUtility {
drawCircle(Graphics2D g2d, double radius, int xCenter, int yCenter) {
draw a circle in software mode
}
drawImage(Graphics2D g2d, Image image, int x, int y) {
draw an image in software mode
}
drawText(Graphics2D g2d, String text, int x, int y) {
draw text in software mode
}
}
These classes separate the code specifying what should be drawn in the classes extending GameWindow from the code specifying how things should be drawn in the classes implementing RendererUtility. So, regardless of which window you're in, the proper rendering methods are used for either hardware accellerated rendering or software only rendering.
Something like this is done somewhere in the Java API, so this might not be necessary for most people. However, one possibility would be to use JOGL for computers with OpenGL support (giving them the best performance possible) and the regular Java rendering for computers without it (allowing the program to run on them even though they don't have OpenGL). The code for that could be similar, though this might not be the best way to do things.
Copyright (C) 2008 Steven Fletcher. All rights reserved.