Composite Design Pattern in Ruby

1. Definition

The Composite Design Pattern lets clients treat individual objects and compositions of objects uniformly. In other words, it allows you to compose objects into tree structures to represent part-whole hierarchies.

2. Problem Statement

Suppose you have individual objects and also compositions of these objects. It becomes a challenge to treat them in the same way, especially when operations and behaviors need to be applied.

3. Solution

The Composite pattern suggests introducing a shared interface for both simple and complex objects. If we see a system as a tree structure, leaf nodes in the tree can represent simple objects while branches or nodes can represent complex objects (compositions).

4. Real-World Use Cases

1. Graphic systems where shapes can be made up of simpler shapes.

2. Organizational structures (e.g., a company's departments and employees).

3. File and directory systems.

5. Implementation Steps

1. Define a Component interface with methods that make sense for both simple and complex components.

2. Create Leaf classes that implement the Component interface.

3. Create Composite classes that also implement the Component interface, and can store child components.

4. Client code can treat both Leaf and Composite objects uniformly.

6. Implementation in Ruby

# Step 1: Component Interface module GraphicComponent def draw raise NotImplementedError, 'Subclasses must define `draw`.' end def add(component) end def remove(component) end end # Step 2: Leaf Classes class Dot include GraphicComponent def draw "Drawing a dot." end end class Line include GraphicComponent def draw "Drawing a line." end end # Step 3: Composite Class class CompoundGraphic include GraphicComponent def initialize @children = [] end def draw @children.map(&:draw).join("\n") end def add(component) @children << component end def remove(component) @children.delete(component) end end # Step 4: Client Code compound_graphic = CompoundGraphic.new compound_graphic.add(Dot.new) compound_graphic.add(Line.new) puts compound_graphic.draw 

Output:

Drawing a dot. Drawing a line. 

Explanation:

1. GraphicComponent serves as the common interface for both simple (Leaf) and complex (Composite) objects.

2. Dot and Line are leaf nodes. They don't have children and they implement the draw method.

3. CompoundGraphic is the composite node. It can have children (both Leaf and Composite), and its drawing method delegates the drawing operation to its children.

4. The client code demonstrates how to create composite structures and treat single and composite objects uniformly.

7. When to use?

Use the Composite Design Pattern when:

1. You need to represent part-whole hierarchies of objects.

2. You want clients to be able to ignore the difference between individual objects and compositions.

3. You want a unified interface for individual and composed objects.


Comments