Bridge pattern
A bridge (English bridge pattern ) is in software development, a structural pattern (English structural pattern) and serves to separate the implementation of its abstraction (interface), which both can be changed independently. It is a design pattern known as GoF patterns (see Gang of Four ).
Problem
Normally, an implementation by inheritance of abstraction is realized. However, this can cause the inheritance hierarchy both implementations as well as other abstract classes are found. This makes the inheritance hierarchy confusing and difficult to maintain.
Solution
The abstract classes and the implementations in two different hierarchies managed as first and second gains, the clarity of the application is independent of the implementation.
General Use
A bridge is used when
- Should be both abstraction and implementation of extensible and a permanent connection between abstraction and implementation is to be prevented,
- To be changes in the implementation without affecting the clients,
- The implementation on the client is to remain hidden, or
- The implementation of the different classes to be used simultaneously.
UML diagram
Actors
The abstraction (in this example List) defined on the one hand, the interface of abstraction, on the other hand she holds a reference to an implementor. The SpezAbstraktion (in the example: SortedList ) extends the interface. The implementor (in the example: ListImpl ) defines the interface implementation. It can therefore be significantly different from the interface abstraction. The KonkrImplementierer (in the example: ArrayList ) contains a concrete implementation through implementation of the interface.
Benefits
The benefits of a bridge are that abstraction and implementation are decoupled. The implementation is still changed dynamically during runtime and the extensibility of abstraction and implementation is improved.
By specifying a parameter in the generation of an abstraction, the implementation can be selected, also the implementation for the client is completely hidden. A strong increase in the number of classes can be avoided.
Code examples
Java
Abstract class Printer { protected PrintingImpl impl; public Printer ( PrintingImpl impl ) { this.impl = impl; } public abstract void print (); public PrintingImpl getImpl () { return impl; } public void setImpl ( PrintingImpl impl ) { this.impl = impl; } } class APrinter extends Printer { public APrinter ( PrintingImpl impl ) { super ( impl ); } @ Override public void print () { impl.print ("A" ); } } class BPrinter extends Printer { public BPrinter ( PrintingImpl impl ) { super ( impl ); } @ Override public void print () { impl.print ("B" ); } } interface PrintingImpl { public void print (String what); } PlainTextPrintingImpl class implements PrintingImpl { @ Override public void print (String what) { System.out.println ( what); } } HTMLPrintingImpl class implements PrintingImpl { @ Override public void print (String what) { System.out.println ("
\ n \ t " what " < / em > \ n < / p >"); } } public class Main { public static void main ( String [ ] args ) { Printer printer; PrintingImpl plainImpl = new PlainTextPrintingImpl (); PrintingImpl htmlImpl = new HTMLPrintingImpl (); printer = new APrinter ( plainImpl ); Printer.Print (); / * The PrintingImpl can easily be replaced at runtime * Is because the implementation of the abstract * Is decoupled. * / printer.setImpl ( htmlImpl ); Printer.Print (); / * Likewise, (similar to the Strategy pattern) of * Printer even be changed at runtime. * / printer = new BPrinter ( plainImpl ); Printer.Print (); printer.setImpl ( htmlImpl ); Printer.Print (); } } Ruby
Class Abstraction def initialize ( implementor ) @ implementor implementor = end def operational raise ' Implementor object does not respond to the operational method ' [email protected]_to? (: operation ) implementor.operation @ end end class RefinedAbstraction < Abstraction def operational puts ' Start process ...' super end end class implementor def operational Execute Important Steps ' puts end end class ConcreteImplementorA < implementor def operational super Execute Additional steps ' puts end end class ConcreteImplementorB < implementor def operational super puts ' Other, perform additional steps ' end end normal_with_a = Abstraction.new ( ConcreteImplementorA.new ) normal_with_a.operation # Execute Important Steps # Perform additional steps normal_with_b = Abstraction.new ( ConcreteImplementorB.new ) normal_with_b.operation # Execute Important Steps # Run Other, additional steps refined_with_a = RefinedAbstraction.new ( ConcreteImplementorA.new ) refined_with_a.operation # Start process ... # Execute Important Steps # Perform additional steps refined_with_b = RefinedAbstraction.new ( ConcreteImplementorB.new ) refined_with_b.operation # Start process ... # Execute Important Steps # Run Other, additional steps Related design patterns
To generate the implementation object of the bridge, an Abstract Factory can be used.
An adapter is apparently similar to the bridge. However, the adapter of a subsequent adjustment of a class to an interface is used, while the bridge is a deliberate decision to decouple. Both design patterns are so contradictory, but can look very similar in their implementation.