Composite means made up of several different elements. So this pattern allows you to ignore the differences and combine different things into one treat them as such. After you combined several things, you’ll realize that you’re creating a tree pattern as well.
Assume you’re using an image editor program. You’ll greatly benefit from organising layers as an individual and as a group.
Here is an example I really liked:
class GraphicObject: def __init__(self, color=None): self.color = color self.children = [] self._name = 'Group' @property def name(self): return self._name def _print(self, items, depth): items.append('*' * depth) if self.color: items.append(self.color) items.append(f'{self.name}\n') for child in self.children: child._print(items, depth + 1) def __str__(self): items = [] self._print(items, 0) return ''.join(items) class Circle(GraphicObject): @property def name(self): return 'Circle' class Square(GraphicObject): @property def name(self): return 'Square' if __name__ == '__main__': drawing = GraphicObject() drawing._name = 'My Drawing' drawing.children.append(Square('Red')) drawing.children.append(Circle('Yellow')) group = GraphicObject() group.children.append(Circle('Blue')) group.children.append(Square('Blue')) drawing.children.append(group) print(drawing)
If you used Keras or Tensorflow you would’ve seen that you can add neurons to layers, the design pattern used there is the same. Here is an example of this:
from abc import ABC from collections.abc import Iterable class Connectable(Iterable, ABC): def connect_to(self, other): if self == other: return for s in self: for o in other: s.outputs.append(o) o.inputs.append(s) class Neuron(Connectable): def __init__(self, name): self.name = name self.inputs = [] self.outputs = [] def __iter__(self): yield self def __str__(self): return f'{self.name}, {len(self.inputs)} inputs, {len(self.outputs)} outputs' class NeuronLayer(list, Connectable): def __init__(self, name, count): super().__init__() self.name = name for x in range(0, count): self.append(Neuron(f'{name}-{x}')) def __str__(self): return f'{self.name} with {len(self)} neurons' def connect_to(self, other): if self == other: return for s in self: for o in other: s.outputs.append(o) o.inputs.append(s) if __name__ == '__main__': neuron1 = Neuron('n1') neuron2 = Neuron('n2') layer1 = NeuronLayer('L1', 3) layer2 = NeuronLayer('L2', 4) neuron1.connect_to(neuron2) neuron1.connect_to(layer1) layer1.connect_to(neuron2) layer1.connect_to(layer2) print(neuron1) print(neuron2) print(layer1) print(layer2)
Resources:
Design Patterns in Python