Difference between revisions of "Bridge"
(→Applicability) |
(→Consequences) |
||
Line 37: | Line 37: | ||
== Consequences == | == Consequences == | ||
The Bridge pattern has the following consequence: | The Bridge pattern has the following consequence: | ||
− | |||
<li>'''Decoupling interface and implementation''' - inheritance tightly couples an abstraction with an implementation at compile time. Bridge pattern can be used to avoid the binding between abstraction and implementation and to select implenetation at run time</li> | <li>'''Decoupling interface and implementation''' - inheritance tightly couples an abstraction with an implementation at compile time. Bridge pattern can be used to avoid the binding between abstraction and implementation and to select implenetation at run time</li> | ||
<li>'''Improved extensibility''' - extend the Abstraction and Implementor hierarchies independently</li> | <li>'''Improved extensibility''' - extend the Abstraction and Implementor hierarchies independently</li> | ||
Line 45: | Line 44: | ||
<li>'''Reduction in the number of sub classes'''</li> | <li>'''Reduction in the number of sub classes'''</li> | ||
<li>'''Cleaner code and Reduction in executable size'''</li> | <li>'''Cleaner code and Reduction in executable size'''</li> | ||
− | |||
== Implementation == | == Implementation == |
Revision as of 19:52, 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
Refined Abstraction
Implementor
Concrete Implementor
Consequences
The Bridge pattern has the following consequence:
Implementation
When applying the Bridge pattern, consider the following implementation issues:
- Only one Implementor
- Creating the right Implementor object
- Sharing implementors
- Using multiple inheritance
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(); } } }
References
- Wikipedia.com - Bridge pattern
- A Survey of Common Design Patterns
- DoFactory.com - Bridge Design Pattern
- Design Class Diagrams - Bridge
- Gamma, E., Helm, R., Johnson, R., Vlissides, J. (1995). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. ISBN 0-201-63361-2