Mr. Latte


Lesson 11 of 13

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.

Looking for a product partner? Founders, teams, businesses: from problem framing to launch.