Welcome to this comprehensive guide on the Composite Pattern in Python! This tutorial is designed to help you understand this design pattern from scratch, making it accessible for beginners and useful for intermediates. Let's dive in!
The Composite Pattern is a behavioral design pattern that lets clients treat individual objects and compositions of objects uniformly. It is used to represent part-whole hierarchies, allowing clients to work with both simple and complex objects in the same way.
š” Pro Tip: This pattern is particularly useful when dealing with tree-like structures such as folders and files in a file system, or nodes in a network.
To implement the Composite Pattern in Python, we need two types of objects:
Let's create a simple example of a folder structure:
class File:
def __init__(self, name):
self.name = name
def display(self):
print(f"File: {self.name}")
class Folder:
def __init__(self, name):
self.name = name
self.contents = []
def add_content(self, content):
self.contents.append(content)
def display(self):
print(f"Folder: {self.name}")
for content in self.contents:
content.display()
# Example usage
root_folder = Folder("Root")
folder1 = Folder("Folder1")
file1 = File("File1.txt")
file2 = File("File2.txt")
root_folder.add_content(folder1)
folder1.add_content(file1)
folder1.add_content(file2)
root_folder.display()In this example, we have a File and Folder class, both with a display method. The Folder class can contain other objects and can add them using the add_content method.
š Note: The Composite Pattern allows us to treat individual files and folders uniformly, as both have a display method.
Now let's take our example a step further by implementing the Command Pattern along with the Composite Pattern to create a simple text editor.
class Command:
def execute(self, editor):
pass
class CreateFileCommand(Command):
def __init__(self, name):
self.name = name
def execute(self, editor):
editor.create_file(self.name)
class EditFileCommand(Command):
def __init__(self, name, content):
self.name = name
self.content = content
def execute(self, editor):
editor.edit_file(self.name, self.content)
class Document:
def __init__(self, name):
self.name = name
self.content = ""
def create_file(self, name):
print(f"Creating new document: {name}")
def edit_file(self, name, content):
print(f"Editing document: {name}")
self.content = content
class TextEditor:
def __init__(self):
self.root_document = Document("Root")
def execute_command(self, command):
command.execute(self.root_document)
# Example usage
create_file_command = CreateFileCommand("Document1.txt")
edit_file_command = EditFileCommand("Document1.txt", "Hello, World!")
editor = TextEditor()
editor.execute_command(create_file_command)
editor.execute_command(edit_file_command)
# Simulates saving the document
editor.root_document.create_file("Saved_Document1.txt")In this example, we have a Command interface, CreateFileCommand, and EditFileCommand classes. The Document class represents our leaves, and the TextEditor class represents our composites. By implementing the Command Pattern, we can encapsulate commands and parameters, making it easy to create, edit, and save documents.
Which of the following classes represent composites in our TextEditor example?
Congratulations on learning the basics of the Composite Pattern in Python! With this knowledge, you can now create complex hierarchical structures in your code and treat individual objects and compositions uniformly. Happy coding! š