Das Bridge Pattern ist ein Strukturmuster, das die Entkopplung von Abstraktion und Implementierung ermöglicht. Es erlaubt, beide unabhängig voneinander zu ändern. Dieses Muster wird verwendet, wenn die Abstraktion und ihre Implementierung in einer Klasse fest miteinander verknüpft sind. Durch das Bridge Pattern kann die Implementierung unabhängig von der Abstraktion verändert werden, ohne dass beides gleichzeitig angepasst werden muss.
Was ist das Bridge Pattern?
Das Bridge Pattern zielt darauf ab, die komplexe Verknüpfung zwischen Abstraktionen und ihren Implementierungen zu vermeiden. Normalerweise befinden sich sowohl die Abstraktion als auch die Implementierung in einer Klasse. Das führt dazu, dass Änderungen an einer der beiden Komponenten auch Änderungen an der anderen erfordern. Das Bridge Pattern löst dieses Problem, indem es die Abstraktion von der Implementierung trennt.
Dieses Muster ist besonders nützlich, wenn es mehrere Varianten einer Abstraktion gibt und die Implementierung verschiedene mögliche Varianten haben kann. Statt mehrere vererbte Klassenhierarchien zu erstellen, ermöglicht es das Bridge Pattern, die Abstraktion und Implementierung zu trennen und beide unabhängig voneinander zu erweitern.
Struktur des Bridge Patterns
- Abstraktion: Die abstrakte Klasse oder Schnittstelle, die eine Referenz auf ein Implementierungsobjekt hält. Sie definiert Methoden, die den konkreten Implementierungen delegiert werden.
- RefinedAbstraction: Eine Erweiterung der Abstraktion. Diese Klasse enthält zusätzliche Methoden und ruft die Implementierungsmethoden über die Bridge auf.
- Implementer: Eine Schnittstelle, die die Implementierungsmethoden definiert. Sie stellt die grundlegenden Operationen bereit, die von der Abstraktion benötigt werden.
- ConcreteImplementer: Die konkrete Klasse, die die Implementer-Schnittstelle implementiert. Sie stellt die eigentliche Implementierung der Methoden bereit.
Beispiel des Bridge Patterns in C++
Angenommen, wir haben ein System zur Darstellung von Formen, und diese Formen können in verschiedenen Farben dargestellt werden. Das Bridge Pattern hilft uns, die Form und die Farbe voneinander zu trennen, sodass wir leicht neue Formen oder Farben hinzufügen können, ohne die bestehende Struktur zu ändern.
#include <iostream>
#include <string>
// Implementer: Schnittstelle für die Implementierungen
class Color {
public:
virtual void fillColor() const = 0;
virtual ~Color() = default;
};
// ConcreteImplementer: Konkrete Implementierung der Farbe
class Red : public Color {
public:
void fillColor() const override {
std::cout << "Rot ausfüllen." << std::endl;
}
};
class Blue : public Color {
public:
void fillColor() const override {
std::cout << "Blau ausfüllen." << std::endl;
}
};
// Abstraktion: Die abstrakte Form-Schnittstelle
class Shape {
protected:
Color* color; // Referenz auf die Implementierung
public:
Shape(Color* color) : color(color) {}
virtual void draw() const = 0; // Abstrakte Methode
virtual ~Shape() = default;
};
// RefinedAbstraction: Eine konkrete Form
class Circle : public Shape {
public:
Circle(Color* color) : Shape(color) {}
void draw() const override {
std::cout << "Kreis zeichnen. ";
color->fillColor();
}
};
class Square : public Shape {
public:
Square(Color* color) : Shape(color) {}
void draw() const override {
std::cout << "Quadrat zeichnen. ";
color->fillColor();
}
};
// Client-Code
int main() {
Color* red = new Red(); // Erstelle eine rote Farbe
Color* blue = new Blue(); // Erstelle eine blaue Farbe
Shape* circle = new Circle(red); // Erstelle einen roten Kreis
Shape* square = new Square(blue); // Erstelle ein blaues Quadrat
circle->draw(); // Zeichne roten Kreis
square->draw(); // Zeichne blaues Quadrat
delete red;
delete blue;
delete circle;
delete square;
return 0;
}
Erklärung des C++-Beispiels
- Implementer: Die
Color
-Schnittstelle definiert die MethodefillColor()
, die in den konkreten Farbklassen (Red
undBlue
) implementiert wird. Diese Klassen repräsentieren die verschiedenen Implementierungen der Farbe. - ConcreteImplementer:
Red
undBlue
sind konkrete Implementierungen derColor
-Schnittstelle. Jede dieser Klassen stellt eine Methode bereit, die die entsprechende Farbe ausfüllt. - Abstraktion: Die
Shape
-Klasse ist die abstrakte Klasse, die diedraw()
-Methode definiert. Sie hält eine Referenz auf einColor
-Objekt, das die Farbe der Form bestimmt. - RefinedAbstraction:
Circle
undSquare
sind konkrete Erweiterungen derShape
-Klasse. Beide verwenden diefillColor()
-Methode desColor
-Objekts, um ihre Farbe zu füllen.
Vorteile des Bridge Patterns
- Flexibilität: Das Bridge Pattern trennt die Abstraktion von ihrer Implementierung. Das ermöglicht es, die Abstraktion oder Implementierung unabhängig voneinander zu ändern, ohne dass das andere betroffen ist.
- Erweiterbarkeit: Durch die Trennung von Abstraktion und Implementierung können neue Abstraktionen und Implementierungen hinzugefügt werden, ohne dass der bestehende Code modifiziert werden muss.
- Vermeidung von Vererbungshierarchien: Anstatt eine komplexe Vererbungshierarchie für jede Kombination aus Abstraktion und Implementierung zu erstellen, können wir das Bridge Pattern verwenden, um eine klare Trennung zwischen beiden zu erreichen.
- Erleichterte Wartung: Da die Implementierung von der Abstraktion getrennt ist, kann die Wartung der Software einfacher werden, weil Änderungen an einer der beiden Seiten keine Auswirkungen auf die andere haben.
Nachteile des Bridge Patterns
- Komplexität: Das Bridge Pattern führt zu einer höheren Komplexität, da mehrere Klassen und Schnittstellen erstellt werden müssen. Für einfache Anwendungen kann dies überflüssig sein.
- Erhöhter Aufwand für die Implementierung: In einigen Fällen kann es schwierig sein, die genaue Trennung von Abstraktion und Implementierung zu bestimmen. Dies kann zu zusätzlichem Aufwand führen, um das Muster richtig zu implementieren.
- Wartungsaufwand bei vielen Abstraktionen: Wenn es viele Abstraktionen und Implementierungen gibt, kann das System mit einer Vielzahl von Klassen und Verbindungen überladen werden.
Fazit
Das Bridge Pattern ist ein sehr effektives Muster, um die Entkopplung von Abstraktion und Implementierung zu ermöglichen. Es verbessert die Flexibilität und Erweiterbarkeit eines Systems, da es Änderungen an einer Seite (Abstraktion oder Implementierung) erlaubt, ohne die andere Seite zu beeinflussen. In C++ kann das Muster leicht implementiert werden, indem eine Abstraktionsebene eingeführt wird, die über eine Implementierungsklasse auf die konkrete Funktionalität zugreift.
Obwohl das Muster einige Nachteile in Bezug auf die Komplexität mit sich bringen kann, ist es besonders nützlich in Szenarien, in denen mehrere Abstraktionen und Implementierungen miteinander kombiniert werden müssen.
Zurück zur Liste der Pattern: Liste der Design-Pattern