|
1 | 1 | # The Composite Pattern (Structural) |
2 | 2 |
|
3 | | -## Intent |
| 3 | +## Purpose |
4 | 4 |
|
5 | | -The Composite pattern is used to organize and structure complex tree structures made up of objects where each object can be treated individually or collectively. It provides a way to compose objects into tree structures and then work with these structures as if they were individual objects. |
| 5 | +The Composite pattern is used to treat individual objects and groups of objects in a uniform way. It allows you to build tree-like structures (like folders, menus, or graphical elements) where each part of the tree can be treated the same—whether it's a single item or a group of items. |
6 | 6 |
|
7 | | -## Problem It Solves |
| 7 | +## The Problem It Solves |
8 | 8 |
|
9 | | -This design pattern addresses the problem of treating individual objects and compositions uniformly, which simplifies code management and organization. It allows clients to treat complex trees structured as well-defined data structures (individual objects) in a uniform manner. |
| 9 | +In many applications, you may need to work with structures made of both simple and complex elements. Without the Composite pattern, you’d have to write separate logic to handle individual items and groups, leading to repetitive code. This pattern unifies them under a common interface, simplifying how they’re managed and manipulated. |
10 | 10 |
|
11 | 11 | ## When to Use It |
12 | 12 |
|
13 | | -The Composite pattern is ideal when you want to create complex tree structures where each node can be treated individually or collectively, making it suitable for use cases such as file systems, HTML documents, and database queries. |
| 13 | +Use the Composite pattern when: |
| 14 | + |
| 15 | +* You need to represent part-whole hierarchies (e.g., file systems, document outlines). |
| 16 | +* You want to treat individual objects and groups of objects uniformly. |
| 17 | +* You need to support recursive structures, such as trees or nested containers. |
14 | 18 |
|
15 | 19 | ## When NOT to Use It |
16 | 20 |
|
17 | | -It's not a good idea to overuse the Composite pattern because it might make code more complicated than necessary. If your application doesn’t require complex tree structures or hierarchies, using simpler patterns like classes could be sufficient. |
| 21 | +Avoid this pattern if: |
| 22 | + |
| 23 | +* Your structure is flat and doesn’t benefit from a hierarchy. |
| 24 | +* Adding abstraction through a component interface makes your code unnecessarily complex. |
| 25 | +* Simpler class designs can get the job done more clearly. |
18 | 26 |
|
19 | 27 | ## How It Works |
20 | 28 |
|
21 | | -The Composite pattern involves three main components: Component (abstract base class), Leaf (concrete component with no children) and Composite (concrete component with sub-components). The Component interface declares common operations for both simple and complex objects of a composition. A client uses these classes to work with the compositions in a uniform manner. |
| 29 | +The pattern involves three core parts: |
| 30 | + |
| 31 | +1. **Component** – The base interface or abstract class that defines common operations. |
| 32 | +2. **Leaf** – Represents the individual objects with no children. |
| 33 | +3. **Composite** – Represents complex objects that can have child components (both leaves and other composites). |
| 34 | + |
| 35 | +The key is that both `Leaf` and `Composite` implement the same interface, allowing client code to interact with them the same way. |
22 | 36 |
|
23 | 37 | ## Real-World Analogy |
24 | 38 |
|
25 | | -Imagine you have a family tree, where each person can be an individual leaf (you), or they could be part of a larger group (your siblings). If your family grows, it's not uncommon for new members to join the group - just like how a composite object can contain other composites or leaves. |
| 39 | +Imagine a company org chart. An individual employee is a leaf, while a department head (composite) manages a group of employees and possibly other departments. Whether you're interacting with an individual or a department, you treat them the same when asking for a task report. |
26 | 40 |
|
27 | 41 | ## Simplified Example |
28 | 42 |
|
29 | | -Here is a simplified example: |
| 43 | +Here’s a basic example in Python: |
30 | 44 |
|
31 | 45 | ```python |
32 | | -class Component: # Abstract base class |
33 | | - def operation(self) -> str: pass |
| 46 | +from typing import List |
34 | 47 |
|
35 | | -class Leaf(Component): # Concrete component with no children |
36 | | - def __init__(self, name: str) -> None: self.name = name |
37 | | - def operation(self) -> str: return f"Leaf({self.name})" |
| 48 | +class Component: |
| 49 | + def operation(self) -> str: |
| 50 | + pass |
38 | 51 |
|
39 | | -class Composite(Component): # Concrete component with sub-components |
40 | | - def __init__(self, name: str) -> None: |
| 52 | +class Leaf(Component): |
| 53 | + def __init__(self, name: str): |
| 54 | + self.name = name |
| 55 | + |
| 56 | + def operation(self) -> str: |
| 57 | + return f"Leaf({self.name})" |
| 58 | + |
| 59 | +class Composite(Component): |
| 60 | + def __init__(self, name: str): |
41 | 61 | self.name = name |
42 | 62 | self._children: List[Component] = [] |
43 | | - |
44 | | - def add(self, component: Component) -> None: self._children.append(component) |
45 | | - def remove(self, component: Component) -> None: self._children.remove(component) |
46 | | - def operation(self) -> str: |
| 63 | + |
| 64 | + def add(self, component: Component) -> None: |
| 65 | + self._children.append(component) |
| 66 | + |
| 67 | + def remove(self, component: Component) -> None: |
| 68 | + self._children.remove(component) |
| 69 | + |
| 70 | + def operation(self) -> str: |
47 | 71 | results = [child.operation() for child in self._children] |
48 | 72 | return f"Composite({self.name})[{' + '.join(results)}]" |
49 | 73 | ``` |
50 | 74 |
|
51 | | -## See Also |
| 75 | +### Example Usage: |
| 76 | + |
| 77 | +```python |
| 78 | +root = Composite("root") |
| 79 | +leaf1 = Leaf("A") |
| 80 | +leaf2 = Leaf("B") |
| 81 | +subtree = Composite("branch") |
| 82 | +subtree.add(Leaf("C")) |
| 83 | + |
| 84 | +root.add(leaf1) |
| 85 | +root.add(subtree) |
| 86 | +root.add(leaf2) |
| 87 | + |
| 88 | +print(root.operation()) # Composite(root)[Leaf(A) + Composite(branch)[Leaf(C)] + Leaf(B)] |
| 89 | +``` |
| 90 | + |
| 91 | +## Learn More |
52 | 92 |
|
53 | | -The corresponding Python file can be found [here](https://github.com/taggedzi/python-design-pattern-rag/blob/main/patterns/structural/composite.py). |
| 93 | +For the full implementation in Python, visit: |
| 94 | +[Composite Pattern on GitHub](https://github.com/taggedzi/python-design-pattern-rag/blob/main/patterns/structural/composite.py) |
0 commit comments