រចនាសម្ព័ន្ធ កម្រិតស្មុគស្មាញ: មធ្យម

Composite in Go

Treat individual objects and object groups uniformly so recursive tree structures stay simple to traverse and aggregate.

The Problem

Tree-shaped data appears everywhere: category hierarchies, organization charts, nested menu structures, and bundle catalogs. Without a common contract, callers need different code paths for leaves and groups, which makes traversal and aggregation noisy.

The Solution

Composite gives both leaves and containers a shared interface. In Go, that often means a small behavior contract plus one composite type that recursively stores children. The caller can then calculate totals or render structure without caring whether it is visiting one node or a whole branch.

Structure

  • Component interface: CatalogNode defines the behavior common to leaves and groups.
  • Leaf: Product has no children and returns its own price.
  • Composite: Category stores child nodes and aggregates over them.
  • Client: Traverses the tree through the shared interface.

Implementation

This example models a nested catalog where categories can contain products or subcategories. The same interface supports recursive rendering and total price aggregation for the entire tree.

package main

import "strings"

type CatalogNode interface {
	Price() int
	Render(level int) string
}

func pad(level int) string {
	return strings.Repeat("  ", level)
}

Best Practices

  • Keep the component interface small so both leaves and composites can implement it naturally.
  • Let the composite own recursion. Clients should not need special cases for children.
  • Avoid stuffing child-management methods into the shared interface unless leaves can handle them sensibly.
  • Use Composite for real tree structures, not just any list of items.
  • If traversal logic grows complex, pair Composite with Iterator or Visitor instead of bloating the node interface.

When to Use

  • You work with tree-shaped data and want uniform treatment of leaves and branches.
  • Aggregation or rendering should work recursively across nested groups.
  • Callers should not need explicit leaf-versus-composite branching.

When NOT to Use

  • The data is not naturally hierarchical.
  • A flat slice and helper functions would be simpler.
  • The shared interface would force unnatural methods onto leaves.