skipnothing/Design Patterns

Composite

Your total_size(node) function opens with if isinstance(node, Folder), recurses into the children, and re-asks the same question at every level. Add a zip-archive node and you're back editing that one function, and every other function that walks the tree.

  • ▸The caller stops asking "file or folder?", both answer the same size() call.
  • ▸The isinstance check doesn't move elsewhere in the caller, it leaves the caller entirely and becomes recursion on the folder.
  • ▸Put add() on every node and a file ends up with an add() method whose only job is to throw.
01

A type check at every node

You want the total size of a directory. A file has a byte count; a folder doesn't, its size is the sum of what's inside it. So the function forks the moment it starts:

def total_size(node):
    if isinstance(node, File):
        return node.bytes
    else:  # a folder
        return sum(total_size(child) for child in node.children)

That isinstance fork is the whole function. And because folders contain folders, the recursion drags it down every level: each call re-asks "file or folder?" before it can do anything. du on the command line walks a tree exactly like this.

Now add a third kind of node, a symlink, or a zip you want to size by its uncompressed contents. The fork grows an elif, and it grows it here and in every other function that walks the tree: count_files, find, render_tree. The type test isn't in one place. It's copied into every operation that touches the structure, and each copy has to be kept in sync.

THE FORK THAT RIDES THE RECURSION DOWN

Keep going, sign up to unlock the rest

4 more parts in this topic, plus 18+ more topics in Design Patterns.

Sign up, it's freeSee the full Design Patterns
Structural Patterns0/5#7 Decorator
#9 Adapter