Difference between revisions of "Bridge"
(→Consequences) |
(→Participants) |
||
Line 25: | Line 25: | ||
== Participants == | == Participants == | ||
The classes and/or objects participating in this pattern are: | The classes and/or objects participating in this pattern are: | ||
− | + | <ul> | |
− | <li>defines the abstraction's interface | + | <li>'''Abstraction'''</li> |
− | <li>maintains a reference to an object of type Implementor | + | <ul> |
− | + | <li>defines the abstraction's interface</li> | |
− | <li>extends the interface defined by Abstraction. | + | <li>maintains a reference to an object of type Implementor</li> |
− | + | </ul> | |
− | <li>defines the interface for implementation classes. This interface does not have to correspond exactly to Abstraction's interface; in fact the two interfaces can be quite different. The Implementation interface provides only primitive operations, and Abstraction defines high-level operations based on these primitives. | + | <li>'''Refined Abstraction'''</li> |
− | + | <ul> | |
− | <li>implements the Implementor interface and defines its concrete implementation. | + | <li>extends the interface defined by Abstraction.</li> |
+ | </ul> | ||
+ | <li>'''Implementor'''</li> | ||
+ | <ul> | ||
+ | <li>defines the interface for implementation classes. This interface does not have to correspond exactly to Abstraction's interface; in fact the two interfaces can be quite different. The Implementation interface provides only primitive operations, and Abstraction defines high-level operations based on these primitives.</li> | ||
+ | </ul> | ||
+ | <li>'''Concrete Implementor'''</li> | ||
+ | <ul> | ||
+ | <li>implements the Implementor interface and defines its concrete implementation.</li> | ||
+ | </ul> | ||
+ | </ul> | ||
== Consequences == | == Consequences == |
Revision as of 20:04, 1 March 2007
The Bridge pattern is intended to decouple an abstraction from its implementation so both can vary independently. The Bridge pattern is also know as Handle/Body.
Contents
UML Structure
Here is an example of the Bridge pattern.
Source: Downloaded from http://www.dofactory.com/Patterns/PatternBridge.aspx
Here is another example of the Bridge pattern where it decouples the abstraction from its implementation so that the two can vary independently
Source: Downloaded from http://home.earthlink.net/~huston2/dp/all_uml.html
Applicability
The Bridge pattern is applicable when:
Participants
The classes and/or objects participating in this pattern are:
- Abstraction
- defines the abstraction's interface
- maintains a reference to an object of type Implementor
- Refined Abstraction
- extends the interface defined by Abstraction.
- Implementor
- defines the interface for implementation classes. This interface does not have to correspond exactly to Abstraction's interface; in fact the two interfaces can be quite different. The Implementation interface provides only primitive operations, and Abstraction defines high-level operations based on these primitives.
- Concrete Implementor
- implements the Implementor interface and defines its concrete implementation.
Consequences
The Bridge pattern has the following consequence:
Implementation
When applying the Bridge pattern, consider the following implementation issues:
Code Examples
Real-world Sample code in C#
This real-world code demonstrates the Bridge pattern in which a BusinessObject abstraction is decoupled from the implementation in DataObject. The DataObject implementations can evolve dynamically without changing any clients.
// Bridge pattern -- Real World example using System; using System.Collections; namespace DoFactory.GangOfFour.Bridge.RealWorld { // MainApp test application class MainApp { static void Main() { // Create RefinedAbstraction Customers customers = new Customers("Chicago"); // Set ConcreteImplementor customers.Data = new CustomersData(); // Exercise the bridge customers.Show(); customers.Next(); customers.Show(); customers.Next(); customers.Show(); customers.New("Henry Velasquez"); customers.ShowAll(); // Wait for user Console.Read(); } } // "Abstraction" class CustomersBase { private DataObject dataObject; protected string group; public CustomersBase(string group) { this.group = group; } // Property public DataObject Data { set{ dataObject = value; } get{ return dataObject; } } public virtual void Next() { dataObject.NextRecord(); } public virtual void Prior() { dataObject.PriorRecord(); } public virtual void New(string name) { dataObject.NewRecord(name); } public virtual void Delete(string name) { dataObject.DeleteRecord(name); } public virtual void Show() { dataObject.ShowRecord(); } public virtual void ShowAll() { Console.WriteLine("Customer Group: " + group); dataObject.ShowAllRecords(); } } // "RefinedAbstraction" class Customers : CustomersBase { // Constructor public Customers(string group) : base(group) { } public override void ShowAll() { // Add separator lines Console.WriteLine(); Console.WriteLine ("------------------------"); base.ShowAll(); Console.WriteLine ("------------------------"); } } // "Implementor" abstract class DataObject { public abstract void NextRecord(); public abstract void PriorRecord(); public abstract void NewRecord(string name); public abstract void DeleteRecord(string name); public abstract void ShowRecord(); public abstract void ShowAllRecords(); } // "ConcreteImplementor" class CustomersData : DataObject { private ArrayList customers = new ArrayList(); private int current = 0; public CustomersData() { // Loaded from a database customers.Add("Jim Jones"); customers.Add("Samual Jackson"); customers.Add("Allen Good"); customers.Add("Ann Stills"); customers.Add("Lisa Giolani"); } public override void NextRecord() { if (current <= customers.Count - 1) { current++; } } public override void PriorRecord() { if (current > 0) { current--; } } public override void NewRecord(string name) { customers.Add(name); } public override void DeleteRecord(string name) { customers.Remove(name); } public override void ShowRecord() { Console.WriteLine(customers[current]); } public override void ShowAllRecords() { foreach (string name in customers) { Console.WriteLine(" " + name); } } } }
Sample Code in Java
The following Java program illustrates the 'shape' example given above and will output:
import java.util.*; /** "Implementor" */ interface DrawingAPI { public void drawCircle(double x, double y, double radius); } /** "ConcreteImplementor" 1/2 */ class DrawingAPI1 implements DrawingAPI { public void drawCircle(double x, double y, double radius) { System.out.printf("API1.circle at %f:%f radius %f\n", x, y, radius); } } /** "ConcreteImplementor" 2/2 */ class DrawingAPI2 implements DrawingAPI { public void drawCircle(double x, double y, double radius) { System.out.printf("API2.circle at %f:%f radius %f\n", x, y, radius); } } /** "Abstraction" */ interface Shape { public void draw(); // low-level public void resizeByPercentage(double pct); // high-level } /** "Refined Abstraction" */ class CircleShape implements Shape { private double x, y, radius; private DrawingAPI drawingAPI; public CircleShape(double x, double y, double radius, DrawingAPI drawingAPI) { this.x = x; this.y = y; this.radius = radius; this.drawingAPI = drawingAPI; } // low-level i.e. Implementation specific public void draw() { drawingAPI.drawCircle(x, y, radius); } // high-level i.e. Abstraction specific public void resizeByPercentage(double pct) { radius *= pct; } } /** "Client" */ class BridgePattern { public static void main(String[] args) { Shape[] shapes = new Shape[2]; shapes[0] = new CircleShape(1, 2, 3, new DrawingAPI1()); shapes[1] = new CircleShape(5, 7, 11, new DrawingAPI2()); for (Shape shape : shapes) { shape.resizeByPercentage(2.5); shape.draw(); } } }