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.

146256
de