Usage examples: The Bridge pattern is especially useful when dealing with cross-platform apps, supporting multiple types of database servers or working with several API providers of a certain kind (for example, cloud platforms, social networks, etc.)
Identification: Bridge can be recognized by a clear distinction between some controlling entity and several different platforms that it relies on.
Conceptual Example
This example illustrates the structure of the Bridge design pattern. It focuses on answering these questions:
What classes does it consist of?
What roles do these classes play?
In what way the elements of the pattern are related?
Program.cs: Conceptual example
usingSystem;namespaceRefactoringGuru.DesignPatterns.Bridge.Conceptual{ // The Abstraction defines the interface for the "control" part of the two // class hierarchies. It maintains a reference to an object of the // Implementation hierarchy and delegates all of the real work to this // object.classAbstraction {protectedIImplementation _implementation;publicAbstraction(IImplementation implementation) {this._implementation= implementation; }publicvirtualstringOperation() {return"Abstract: Base operation with:\n"+_implementation.OperationImplementation(); } } // You can extend the Abstraction without changing the Implementation // classes.classExtendedAbstraction:Abstraction {publicExtendedAbstraction(IImplementation implementation) : base(implementation) { }publicoverridestringOperation() {return"ExtendedAbstraction: Extended operation with:\n"+ base._implementation.OperationImplementation(); } } // The Implementation defines the interface for all implementation classes. // It doesn't have to match the Abstraction's interface. In fact, the two // interfaces can be entirely different. Typically the Implementation // interface provides only primitive operations, while the Abstraction // defines higher- level operations based on those primitives.publicinterfaceIImplementation {stringOperationImplementation(); } // Each Concrete Implementation corresponds to a specific platform and // implements the Implementation interface using that platform's API.classConcreteImplementationA:IImplementation {publicstringOperationImplementation() {return"ConcreteImplementationA: The result in platform A.\n"; } }classConcreteImplementationB:IImplementation {publicstringOperationImplementation() {return"ConcreteImplementationB: The result in platform B.\n"; } }classClient { // Except for the initialization phase, where an Abstraction object gets // linked with a specific Implementation object, the client code should // only depend on the Abstraction class. This way the client code can // support any abstraction-implementation combination.publicvoidClientCode(Abstraction abstraction) {Console.Write(abstraction.Operation()); } }classProgram {staticvoidMain(string[] args) {Client client =newClient();Abstraction abstraction; // The client code should be able to work with any pre-configured // abstraction-implementation combination. abstraction =newAbstraction(newConcreteImplementationA());client.ClientCode(abstraction);Console.WriteLine(); abstraction =newExtendedAbstraction(newConcreteImplementationB());client.ClientCode(abstraction); } }}
Output.txt: Execution result
Abstract: Base operation with:
ConcreteImplementationA: The result in platform A.
ExtendedAbstraction: Extended operation with:
ConcreteImplementationA: The result in platform B.