Bridge (design pattern)

from Wikipedia, the free encyclopedia

A bridge (English bridge pattern ) is in the software development , a structural pattern (English structural pattern ), the separation of the implementation of their abstraction ( interface ) is used. This means that both can be changed independently of each other. It is a design pattern of the so-called GoF pattern (see Gang of Four ).

problem

Usually an implementation is done by inheriting the abstraction. However, this can lead to both implementations and other abstract classes being found in the inheritance hierarchy. This makes the inheritance hierarchy cluttered and difficult to maintain.

solution

If the abstract classes and the implementations are managed in two different hierarchies, firstly the clarity gains and secondly the application becomes independent of the implementation.

solution

On the left is the hierarchy of the abstractions (List and SortedList). On the right is the hierarchy of the implementations (ListImpl and ArrayList).

General use

A bridge applies when

  • Both abstraction and implementation should be expandable and a permanent connection between abstraction and implementation should be prevented,
  • Changes to the implementation should have no impact on the client,
  • the implementation should remain hidden from the client, or
  • the implementation should be used by different classes at the same time.

In practice it often happens that the abstraction side is not subdivided as finely as the implementation side. One speaks of a degenerate bridge .

UML diagram

UML diagram: bridge

actors

The abstraction (in the example:) Liston the one hand defines the interface of the abstraction, on the other hand it holds a reference to an implementer. The SpezAbstraktion(in the example:) SortedListextends the interface. The implementer (in the example:) ListImpldefines the interface of the implementation. It can differ considerably from the interface of the abstraction. The KonkrImplementierer(in the example:) ArrayListcontains a concrete implementation by implementing the interface.

advantages

The advantages of a bridge are that abstraction and implementation are decoupled. The implementation can also be changed dynamically during runtime and the extensibility of abstraction and implementation is improved.

The implementation can be selected by specifying a parameter when generating an abstraction, and the implementation is completely hidden from the client. A large 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);
}

class PlainTextPrintingImpl implements PrintingImpl {
    @Override
    public void print(String what) {
        System.out.println(what);
    }
}

class HTMLPrintingImpl implements PrintingImpl {
    @Override
    public void print(String what) {
        System.out.println("<p>\n\t<em>" + 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();

        /* Die PrintingImpl kann problemlos zur Laufzeit ausgetauscht
         * werden, da die Implementierung von der Abstraktion
         * entkoppelt ist. */
        printer.setImpl(htmlImpl);
        printer.print();

        /* Genauso kann (ähnlich wie beim Strategy-Pattern) der
         * Printer selbst zur Laufzeit geändert werden. */
        printer = new BPrinter(plainImpl);
        printer.print();

        printer.setImpl(htmlImpl);
        printer.print();
    }
}

Output:

A
<p>
  <em>A</em>
</p>
B
<p>
  <em>B</em>
</p>

Ruby

class Abstraction
  def initialize(implementor)
    @implementor = implementor
  end

  def operation
    raise 'Implementor-Objekt antwortet nicht auf die operation-Methode'
      unless @implementor.respond_to?(:operation)
    @implementor.operation
  end
end

class RefinedAbstraction < Abstraction
  def operation
    puts 'Starte Vorgang...'
    super
  end
end

class Implementor
  def operation
    puts 'Wichtige Schritte ausführen'
  end
end

class ConcreteImplementorA < Implementor
  def operation
    super
    puts 'Zusätzliche Schritte ausführen'
  end
end

class ConcreteImplementorB < Implementor
  def operation
    super
    puts 'Andere, zusätzliche Schritte ausführen'
  end
end

normal_with_a = Abstraction.new(ConcreteImplementorA.new)
normal_with_a.operation
# Wichtige Schritte ausführen
# Zusätzliche Schritte ausführen

normal_with_b = Abstraction.new(ConcreteImplementorB.new)
normal_with_b.operation
# Wichtige Schritte ausführen
# Andere, zusätzliche Schritte ausführen

refined_with_a = RefinedAbstraction.new(ConcreteImplementorA.new)
refined_with_a.operation
# Starte Vorgang...
# Wichtige Schritte ausführen
# Zusätzliche Schritte ausführen

refined_with_b = RefinedAbstraction.new(ConcreteImplementorB.new)
refined_with_b.operation
# Starte Vorgang...
# Wichtige Schritte ausführen
# Andere, zusätzliche Schritte ausführen

Related design patterns

An abstract factory can be used to generate the implementation object of the bridge .

An adapter is apparently similar to the bridge. However, the adapter is used to subsequently adapt a class to an interface, while the bridge is a targeted decision for decoupling. Both design patterns are thus opposite, but can look very similar in their implementation.

Individual evidence

  1. Erich Gamma , Richard Helm , Ralph Johnson , John Vlissides : Design pattern . 5th edition. Addison-Wesley , 1996, ISBN 3-8273-1862-9 , pp. 186 .