Python-Kompositum-Muster
Das Composite Pattern ist ein strukturelles Entwurfsmuster, das es ermöglicht, Objekte zu Baumstrukturen zusammenzusetzen, um Teil-Ganzes-Hierarchien darzustellen. Das Composite Pattern ermöglicht es Clients, einzelne Objekte und Objektkompositionen einheitlich zu behandeln, ohne sich darum kümmern zu müssen, ob sie mit einem einzelnen Objekt oder der gesamten zusammengesetzten Struktur arbeiten.
Analogie aus dem echten Leben
Stellen Sie sich die Organisationsstruktur eines Dateisystems vor:
- Einzelne Datei: ist die grundlegendste Einheit
- Ordner: kann mehrere Dateien oder andere Ordner enthalten
- Egal, ob Sie eine Datei oder einen Ordner bearbeiten, können Sie Vorgänge wie "Öffnen", "Löschen", "Umbenennen" usw. ausführen.
Diese "Teil-Ganzes"-Hierarchiebeziehung ist ein typisches Anwendungsszenario des Composite Patterns.
Kernkomponenten des Composite-Musters
1. Komponentenschnittstelle (Component)
Dies ist der Kern des Composite-Musters und definiert eine gemeinsame Schnittstelle für alle Objekte (einschließlich Blattknoten und Verbundknoten).
Beispiel
from typing import List
class FileSystemComponent(ABC):
"""Abstrakte Basisklasse für Dateisystemkomponenten"""
def __init__(self, name: str):
self.name = name
self.parent = None
@abstractmethod
def display(self, indent: int = 0) -> None:
"""Komponenteninformationen anzeigen"""
pass
@abstractmethod
def get_size(self) -> int:
"""Komponentengröße abrufen"""
pass
def get_path(self) -> str:
"""Vollständigen Pfad abrufen"""
if self.parent:
return f"{self.parent.get_path()}/{self.name}"
return self.name
2. Blattknoten (Leaf)
Stellt Blattobjekte in der Komposition dar; Blattknoten haben keine Kindknoten.
Beispiel
"""File-Klasse - Blattknoten"""
def __init__(self, name: str, size: int):
super().__init__(name)
self._size = size
def display(self, indent: int = 0) -> None:
"""Dateiinformationen anzeigen"""
spaces = " " * indent
print(f"{spaces}📄 {self.name} ({self._size} bytes)")
def get_size(self) -> int:
"""Dateigröße zurückgeben"""
return self._size
3. Zusammengesetzter Knoten (Composite)
Repräsentiert zusammengesetzte Objekte, die untergeordnete Komponenten enthalten können, und definiert Methoden zum Speichern untergeordneter Komponenten.
Beispiel
"""Directory-Klasse - zusammengesetzter Knoten"""
def __init__(self, name: str):
super().__init__(name)
self._children: List[FileSystemComponent] = []
def add(self, component: FileSystemComponent) -> None:
"""Untergeordnete Komponente hinzufügen"""
component.parent = self
self._children.append(component)
def remove(self, component: FileSystemComponent) -> None:
"""Untergeordnete Komponente entfernen"""
self._children.remove(component)
component.parent = None
def display(self, indent: int = 0) -> None:
"""Verzeichnis und alle seine untergeordneten Komponenten anzeigen"""
spaces = " " * indent
print(f"{spaces}📁 {self.name}/")
# Alle untergeordneten Komponenten rekursiv anzeigen
for child in self._children:
child.display(indent + 1)
def get_size(self) -> int:
"""Gesamtgröße des Verzeichnisses berechnen (einschließlich aller untergeordneten Komponenten)"""
total_size = 0
for child in self._children:
total_size += child.get_size()
return total_size
def find_component(self, name: str) -> FileSystemComponent:
"""Findet eine Komponente mit dem angegebenen Namen"""
for child in self._children:
if child.name == name:
return child
if isinstance(child, Directory):
found = child.find_component(name)
if found:
return found
return None
Vollständiges Beispiel: Dateisystem-Simulation
Lassen Sie uns die praktische Anwendung des Composite-Musters anhand eines vollständigen Beispiels demonstrieren:
Beispiel
"""Demonstriert die Verwendung des Composite-Musters"""
# Stammverzeichnis erstellen
root = Directory("root")
# Unterverzeichnis erstellen
documents = Directory("documents")
pictures = Directory("pictures")
music = Directory("music")
# Dateien erstellen
readme = File("README.txt", 1024)
notes = File("notes.md", 2048)
photo1 = File("vacation.jpg", 1536000)
photo2 = File("family.png", 2048000)
song1 = File("song1.mp3", 4096000)
song2 = Datei("song2.mp3", 5120000)
# Verzeichnisstruktur erstellen
root.add(readme)
root.add(documents)
root.add(pictures)
root.add(music)
documents.add(notes)
pictures.add(photo1)
pictures.add(photo2)
music.add(song1)
music.add(song2)
# Die gesamte Dateisystemstruktur anzeigen
print("=== Dateisystemstruktur ===")
root.display()
print("\n=== Größenstatistik ===)
print(f"Gesamtgröße des Root-Verzeichnisses: {root.get_size()} bytes")
print(f"Größe des Bilder-Verzeichnisses: {pictures.get_size()} bytes")
print(f"Größe des Musik-Verzeichnisses: {music.get_size()} bytes")
print("\n=== Pfadinformationen ===)
print(f"Dateipfad: {photo1.get_path()}")
print(f"Verzeichnispfad: {pictures.get_path()}")
print("\n=== Komponente finden ===)
found = root.find_component("song1.mp3")
if found:
print(f"Gefundene Datei: {found.get_path()}")
# Demo ausführen
if __name__ == "__main__":
demonstrate_composite_pattern()
Das Ausführen des obigen Codes erzeugt die folgende Ausgabe:

UML-Klassendiagramm des Composite-Musters

Vor- und Nachteile des Composite-Musters
Vorteile
- Einheitliche Schnittstelle: Clients können einzelne Objekte und zusammengesetzte Objekte konsistent verwenden
- Open/Closed-Prinzip: Es ist einfach, neue Arten von Komponenten hinzuzufügen, ohne vorhandenen Code zu ändern
- Vereinfachter Client-Code: Clients müssen nicht feststellen, ob sie es mit einem einzelnen Objekt oder einem zusammengesetzten Objekt zu tun haben
- Flexible Hierarchie: Kann komplexe Baumstrukturen aufbauen
Nachteile
- Entwurfskomplexität: Eine übermäßig verallgemeinerte Gestaltung kann das System komplex machen
- Typensicherheitsprobleme: In einigen Fällen kann eine Typprüfung zur Laufzeit erforderlich sein
- Leistungsüberlegungen: Bei großen Hierarchien können rekursive Operationen die Leistung beeinträchtigen
Praktische Anwendungsszenarien
1. GUI-Komponentensystem
Beispiel
"""UI-Komponenten-Basisklasse"""
def render(self):
pass
def add(self, component):
pass
class Button(UIComponent):
"""Button - Blattknoten"""
def render(self):
print("Button rendern")
class Panel(UIComponent):
"""Panel - Verbundknoten"""
def __init__(self):
self.children = []
def add(self, component):
self.children.append(component)
def render(self):
print("Rendern des Panels starten")
for child in self.children:
child.render()
print("Rendering-Panel beenden")
2. Verwaltung der Organisationsstruktur
Beispiel
"""Basisklasse für Mitarbeiter"""
def get_salary(self):
pass
class Developer(Employee):
"""Developer - Blattknoten"""
def __init__(self, salary):
self.salary = salary
def get_salary(self):
return self.salary
class Department(Employee):
"""Department - Kompositknoten"""
def __init__(self):
self.employees = []
def add(self, employee):
self.employees.append(employee)
def get_salary(self):
return sum(emp.get_salary() for emp in self.employees)
Praktische Übungen
Übung 1: Erweiterung des Dateisystems
Fügen Sie die folgenden Funktionen zum Dateisystem hinzu:
- Dateikopierfunktion implementieren
- Dateitypfilter-Suche hinzufügen
- Verzeichnisanzeige mit begrenzter Tiefe implementieren
Übung 2: Entwurf des Menüsystems
Entwerfe ein Restaurant-Menüsystem mit den folgenden Anforderungen:
- Ein Menü kann Gerichte oder Untermenüs enthalten
- Gesamtpreis berechnen können
- Filtern von Gerichten nach Kategorie unterstützen
Übung 3: Organigramm
Erstelle ein System für die Organisationsstruktur eines Unternehmens:
- Mitarbeiter können Einzelpersonen oder Abteilungen sein
- Abteilungen können andere Mitarbeiter oder Unterabteilungen enthalten
- Die Gesamtzahl der Personen und das Gesamtgehalt einer Abteilung berechnen können
Zusammenfassung
Das Composite-Muster behandelt einzelne Objekte und Objektkompositionen über eine einheitliche Schnittstelle, wodurch der Client-Code prägnanter und flexibler wird. Dieses Muster eignet sich besonders für Szenarien mit hierarchischen Strukturen, wie Dateisysteme, GUI-Komponenten, Organisationsstrukturen und so weiter.
Kernpunkte:
- Die Komponentenschnittstelle definiert gemeinsame Operationen für alle Objekte
- Blattknoten implementieren grundlegende Funktionalität
- Kompositknoten verwalten untergeordnete Komponenten und bieten aggregierte Operationen
- Clients müssen nicht zwischen einzelnen Objekten und Objektkompositionen unterscheiden