Composite: Treat Items and Groups Uniformly
A basket contains individual products and bundles. Instead of checking every type when calculating a price, ask each object for its total.
Leaves return values; groups combine children
class Item:
def __init__(self, price):
self.price = price
def total(self):
return self.price
class Bundle:
def __init__(self, children):
self.children = list(children)
def total(self):
return sum(child.total() for child in self.children)
basket = Bundle([Item(1000), Bundle([Item(2000), Item(500)])])
print(basket.total())
The output is 3500. Item returns its price; Bundle adds totals from its children. Nested bundles work through the same call. This is the basic Composite structure.
A shared interface need not include every possible operation. Adding a child only makes sense for groups; leaves need not expose a meaningless add method.
Preserve the tree assumption
A bundle containing itself or an ancestor creates a cycle that can prevent simple recursion from finishing. Also decide whether an item shared by two groups should count twice. Very deep or large structures raise recursion-depth and repeated-work concerns.
Check your understanding
The same item object appears twice in a bundle. How often does this example count its price, and is that necessarily a bug?
Show explanation
Twice. That is correct for purchasing two units, but may be wrong when calculating the size of unique files. The pattern supplies structure; the problem defines what duplication means.