← All patterns
Creational

Builder

Assemble a complex object one readable step at a time, then hand back the finished product.

What Is It?

The Builder pattern separates how an object is assembled from the object itself. Instead of a constructor with nine optional parameters, you call small, named steps — WithHead, WithArmor, WithWeapon — and finish with Build().

In C# builders are usually fluent: every step returns the builder, so the whole recipe reads as a single chained expression. A separate Director can store reusable recipes ("Knight", "Archer") that drive the same builder in a fixed order.

In Unity this is a natural fit for procedurally assembled characters, loot with random affixes, or dungeon rooms: the builder collects choices, validates them, and only at Build() instantiates prefabs and wires components together.

When Is It Used?

Reach for it when an object has many optional parts or settings and most combinations are valid — character customisers, weapon modding, enemy variants for a wave spawner.

It also helps when construction must happen in a particular order or must be validated before the object goes live, such as ensuring a ranged unit always has a weapon.

Skip it for simple objects with two or three fields. A plain constructor, object initialiser or a ScriptableObject preset is less ceremony.

Interactive Demo

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

Code

Assets / Scripts / Creational/ Builder ›BuilderTester.cs
using UnityEngine;

namespace Patterns.Creational.Builder
{
    /// <summary>
    /// Client: builds a custom character by hand and two presets
    /// through the director, all from the same builder instance.
    /// </summary>
    public class BuilderTester : MonoBehaviour
    {
        [SerializeField] private Character characterPrefab;
        [SerializeField] private float spacing = 2f;

        private void Start()
        {
            var builder = new CharacterBuilder(characterPrefab);
            var director = new CharacterDirector(builder);

            Character mage = builder
                .Named("Mage")
                .WithHead(HeadType.Hood)
                .WithWeapon(WeaponType.Staff)
                .WithColor(new Color(0.55f, 0.35f, 0.9f))
                .Build(Vector3.zero);

            Character knight = director.BuildKnight(Vector3.right * spacing);
            Character archer = director.BuildArcher(Vector3.right * spacing * 2f);

            Debug.Log($"{mage.DisplayName} DEF {mage.Defense}");
            Debug.Log($"{knight.DisplayName} DEF {knight.Defense}");
            Debug.Log($"{archer.DisplayName} DEF {archer.Defense}");
        }
    }
}
4 files · namespace Patterns.Creational.BuilderC# · UTF-8 · LF

Advantages & Disadvantages

+ Advantages

  • Construction code is self-documenting: .WithArmor(Plate).WithWeapon(Sword) reads like a sentence.
  • Directors turn common configurations into one-line presets, reused by spawners, editor tools and tests.
  • The product can be immutable after Build(), because all mutation happens inside the builder.

− Disadvantages

  • Adds an extra class (or two) per product type, which is noise for small objects.
  • It is easy to forget to reset a builder between uses and leak parts into the next product.
  • Required parts are not enforced by the compiler; you must validate in Build().

Tips

  1. 01Return this from every step to make the API fluent, and keep step names verb-like (WithX, AddX).
  2. 02Reset internal state at the end of Build() so the same builder instance can be reused safely by a spawner.
  3. 03Keep the builder a plain C# class; only touch Instantiate and components inside Build() so the steps are cheap and testable.
  4. 04Store Director recipes as ScriptableObjects if designers should be able to author new presets without code.
  5. 05Log an error in Build() when a required part is missing — fail at construction time, not in the middle of combat.