Das Flyweight Pattern ist ein Strukturmuster, das verwendet wird, um die Effizienz bei der Nutzung von Objekten zu verbessern. Es hilft, die Anzahl der erstellten Objekte zu reduzieren, indem gemeinsame Objekte wiederverwendet werden. Dies ist besonders nützlich, wenn viele ähnliche Objekte existieren, die sich nur in wenigen Details unterscheiden.
Was ist das Flyweight Pattern?
Das Flyweight Pattern zielt darauf ab, den Speicherverbrauch zu verringern, indem es Objekte teilt. Wenn viele Instanzen eines Objekts ähnliche Eigenschaften besitzen, können diese Eigenschaften ausgelagert und gemeinsam genutzt werden. Dadurch wird der Speicherverbrauch reduziert und die Leistung verbessert.
Das Flyweight Pattern umfasst folgende Komponenten:
- Flyweight: Die gemeinsame Schnittstelle, die von allen Flyweight-Objekten implementiert wird.
- ConcreteFlyweight: Das konkrete Flyweight-Objekt, das den Zustand der Objekte speichert, der geteilt werden kann.
- FlyweightFactory: Eine Fabrik, die die Flyweight-Objekte verwaltet und sie bei Bedarf wiederverwendet.
- Client: Der Client nutzt die Flyweight-Objekte, ohne sich um deren Details zu kümmern.
Beispiel des Flyweight Patterns in C++
Angenommen, wir haben ein System zur Darstellung von Bäumen in einem Wald. Viele Bäume haben ähnliche Eigenschaften wie die Art des Baums oder das Laub. Die einzige Unterscheidung könnte der Standort jedes Baums sein. Anstatt für jeden Baum ein neues Objekt zu erstellen, können wir das Flyweight Pattern verwenden, um die gemeinsam genutzten Eigenschaften zu teilen.
#include <iostream>
#include <memory>
#include <unordered_map>
// Flyweight: Gemeinsame Schnittstelle für Flyweight-Objekte
class Tree {
public:
virtual void display(int x, int y) const = 0;
virtual ~Tree() = default;
};
// ConcreteFlyweight: Ein konkretes Flyweight, das die gemeinsamen Eigenschaften speichert
class ConcreteTree : public Tree {
private:
std::string treeType;
public:
ConcreteTree(const std::string& type) : treeType(type) {}
void display(int x, int y) const override {
std::cout << "Baumtyp: " << treeType << ", Standort: (" << x << ", " << y << ")\n";
}
};
// FlyweightFactory: Eine Fabrik, die Flyweight-Objekte erstellt und verwaltet
class TreeFactory {
private:
std::unordered_map<std::string, std::shared_ptr<Tree>> trees;
public:
std::shared_ptr<Tree> getTree(const std::string& type) {
// Wenn der Baum bereits existiert, wird er wiederverwendet
if (trees.find(type) == trees.end()) {
trees[type] = std::make_shared<ConcreteTree>(type);
}
return trees[type];
}
};
// Client-Code
int main() {
TreeFactory treeFactory;
// Die ersten zwei Bäume teilen sich die gleiche Instanz
std::shared_ptr<Tree> oak1 = treeFactory.getTree("Eiche");
oak1->display(10, 20);
std::shared_ptr<Tree> oak2 = treeFactory.getTree("Eiche");
oak2->display(30, 40);
// Ein anderer Baumtyp wird erstellt
std::shared_ptr<Tree> pine = treeFactory.getTree("Kiefer");
pine->display(50, 60);
// Wiederverwendung der Eiche
oak1->display(70, 80);
return 0;
}
Erklärung des C++-Beispiels
In diesem Beispiel erstellen wir eine TreeFactory, die Flyweight-Objekte verwaltet. Jedes ConcreteTree speichert den Baumtyp (zum Beispiel „Eiche“ oder „Kiefer“), während der Client-Teil für den Baumstandort verantwortlich ist.
- Flyweight: Die
Tree
-Schnittstelle stellt die gemeinsame Methodedisplay()
bereit, die von allen Baumtypen verwendet wird. - ConcreteFlyweight: Die Klasse
ConcreteTree
speichert den gemeinsamen Zustand des Baumes, nämlich den Baumtyp. Sie zeigt auch diedisplay()
-Methode an, die den Baumtyp und den Standort des Baumes anzeigt. - FlyweightFactory: Die
TreeFactory
stellt sicher, dass für jeden Baumtyp nur eine Instanz existiert. Falls bereits ein Baum dieses Typs existiert, wird er wiederverwendet. - Client: Der Client fragt die
TreeFactory
nach einem Baumtyp und übergibt die spezifischen Koordinaten des Baumes. Der Baumtyp wird dann von der Fabrik geliefert, wobei immer dieselbe Instanz für denselben Baumtyp verwendet wird.
Vorteile des Flyweight Patterns
- Speicherersparnis: Durch die Wiederverwendung von Objekten, die denselben Zustand teilen, wird der Speicherverbrauch erheblich reduziert.
- Leistungssteigerung: Die Verwendung von Flyweight-Objekten reduziert die Anzahl der Objekte im Speicher, was die Performance verbessert.
- Skalierbarkeit: Das Muster ist besonders nützlich, wenn viele ähnliche Objekte erstellt werden müssen, wie es in Spielen oder grafischen Anwendungen der Fall ist.
- Wiederverwendbarkeit: Flyweights sind in vielen Kontexten wiederverwendbar. Ein einmal erstelltes Flyweight-Objekt kann immer wieder genutzt werden, was die Konsistenz erhöht.
Nachteile des Flyweight Patterns
- Komplexität der Implementierung: Die Implementierung des Flyweight Patterns kann komplex sein, da die Verwaltung der Flyweight-Objekte und des Zustands schwieriger wird.
- Probleme mit der Thread-Sicherheit: Da mehrere Clients denselben Flyweight verwenden können, können Synchronisierungsprobleme auftreten, wenn mehrere Threads auf dasselbe Objekt zugreifen.
- Erhöhte Anzahl von Klassen: Das Muster kann die Anzahl der Klassen erhöhen, da für jedes Flyweight-Objekt eine konkrete Klasse erstellt werden muss.
- Kombination von Zuständen: Wenn der Zustand nicht gut unterteilt ist, kann es schwierig sein, die Unterschiede zwischen Flyweights und ihren unterschiedlichen Zuständen zu verwalten.
Fazit
Das Flyweight Pattern ist ein leistungsstarkes Muster zur Reduzierung des Speicherverbrauchs und zur Verbesserung der Performance. Es ermöglicht die Wiederverwendung von Objekten, die denselben Zustand teilen, und hilft so, Ressourcen zu sparen. In C++ lässt sich das Muster einfach umsetzen, indem Flyweight-Objekte und eine Fabrik zur Verwaltung dieser Objekte genutzt werden.
Das Flyweight Pattern eignet sich besonders in Systemen, in denen viele ähnliche Objekte existieren, etwa in grafischen Anwendungen, Spielen oder bei der Verwaltung von Ressourcen. Es bietet erhebliche Vorteile in Bezug auf Speicher und Performance, kann jedoch in komplexeren Szenarien schwieriger zu implementieren sein.
Zurück zur Liste der Pattern: Liste der Design-Pattern