← All patterns
Structural

Composite

Treat a single object and a whole tree of objects through the same interface.

What Is It?

Composite arranges objects into a tree where leaves and branches share one interface. A leaf does the work itself; a composite holds children and forwards the call to each of them, usually combining the results on the way back up.

Picture an RTS army. A Soldier has an attack power. A Squad contains soldiers and maybe other squads. An Army contains squads. All of them implement IUnit, so army.GetPower() walks the whole tree and sums it, while soldier.GetPower() simply returns a number. The caller never checks which one it holds.

Unity itself is built on this idea: the Transform hierarchy is a composite, and moving a parent moves every child. The pattern lets your own game data get the same uniform treatment for things like squads, UI menus, quest objectives, skill trees and behaviour trees.

When Is It Used?

Use it whenever your data is naturally a tree and you want to run the same operation at any level: select a squad or a single soldier, mute a whole audio category or one source, complete a quest step or the full quest chain.

It is a strong fit for behaviour trees and dialogue graphs, where a sequence node and an action node must both answer Tick() and return a status.

Avoid it when leaves and branches really need different operations. Forcing an Add(child) method onto a soldier that can never have children just moves the type check to runtime errors.

Interactive Demo

Click the controls and watch the objects collaborate. The console mirrors what the C# code below would log.

Code

Assets / Scripts / Structural/ Composite ›ArmyTester.cs
using UnityEngine;

namespace Patterns.Structural.Composite
{
    /// <summary>
    /// Builds a small army tree and calls the same methods on the root,
    /// a squad and a single soldier.
    /// </summary>
    public class ArmyTester : MonoBehaviour
    {
        private Squad army;

        private void Start()
        {
            var alpha = new Squad("Alpha");
            alpha.Add(new Soldier("Knight", 12));
            alpha.Add(new Soldier("Archer", 8));

            var bravo = new Squad("Bravo");
            bravo.Add(new Soldier("Pikeman", 10));

            army = new Squad("Army");
            army.Add(alpha);
            army.Add(bravo);

            Debug.Log($"Army power: {army.GetPower()}");   // 30
            Debug.Log($"Alpha power: {alpha.GetPower()}"); // 20
        }

        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.Space))
                army.Attack(); // one call, every soldier swings
        }
    }
}
4 files · namespace Patterns.Structural.CompositeC# · UTF-8 · LF

Advantages & Disadvantages

+ Advantages

  • Clients use one interface for one object or ten thousand, so calling code stays tiny.
  • New leaf or composite types slot in without touching existing traversal code.
  • Recursive aggregation (total power, total weight, bounds) falls out naturally.

− Disadvantages

  • The shared interface can become too general, making it hard to restrict which children a composite accepts.
  • Deep trees mean deep recursion; naive per-frame traversal of large hierarchies can show up in the profiler.
  • Debugging a single result means walking the tree to find which node contributed what.

Tips

  1. 01Cache aggregate values and invalidate them when children change (a dirty flag) instead of recomputing every frame.
  2. 02Keep child-management methods (Add, Remove) on the composite type only, not on the shared interface, to stay type-safe.
  3. 03For scene objects, you can lean on GetComponentsInChildren<IUnit>(), but a plain C# tree is faster and easier to test.
  4. 04Guard against cycles if your tree is editable at runtime: never let a squad become its own descendant.
  5. 05Visitors pair well with composites when you need many unrelated operations over the same tree.