← All patterns
Behavioral

Observer

Let one object broadcast changes to any number of listeners without knowing who they are.

What Is It?

The Observer pattern defines a one-to-many relationship: a subject keeps a list of observers and notifies all of them when something interesting happens. The subject never references concrete observer types — it just raises an event.

In C#, this maps naturally onto event Action<T> or UnityEvent. Observers subscribe with += and unsubscribe with -=; the subject calls Invoke and moves on.

A classic Unity example is player health: when PlayerHealth changes, the health bar animates, the audio system plays a hurt sound and the game-over screen waits for Died — yet PlayerHealth has zero dependencies on any of them.

When Is It Used?

Use it whenever one change should trigger reactions in several unrelated systems: UI updates, achievements, analytics, sound, VFX, quest progress.

It shines when you want to add or remove reactions without touching the source. A new achievement system can subscribe to Died without editing the player at all.

Avoid it for tight, ordered sequences where one step must happen before the next — event chains are hard to follow and their call order is not something you should rely on.

Interactive Demo

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

Code

Assets / Scripts / Behavioral/ Observer ›DamageTester.cs
using UnityEngine;

namespace Patterns.Behavioral.Observer
{
    /// <summary>
    /// Drives the subject for testing. Note that it only talks to
    /// PlayerHealth; the UI and audio react on their own.
    /// </summary>
    public class DamageTester : MonoBehaviour
    {
        [SerializeField] private PlayerHealth player;

        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.Space))
                player.TakeDamage(10);

            if (Input.GetKeyDown(KeyCode.H))
                player.Heal(10);
        }
    }
}
4 files · namespace Patterns.Behavioral.ObserverC# · UTF-8 · LF

Advantages & Disadvantages

+ Advantages

  • Subjects and observers are loosely coupled; either side can change independently.
  • New behaviour is added by subscribing, not by modifying existing code (Open/Closed).
  • Maps directly onto built-in C# events, so there is almost no boilerplate.

− Disadvantages

  • Forgetting to unsubscribe causes leaks and calls on destroyed objects (MissingReferenceException).
  • Control flow becomes implicit — it is harder to trace “who reacts to this?” in a debugger.
  • Notification order is not guaranteed; observers that depend on each other become fragile.

Tips

  1. 01Pair += in OnEnable with -= in OnDisable. It is the single most important habit with events in Unity.
  2. 02Prefer event Action<T> for code-only wiring and UnityEvent when designers need to hook things up in the Inspector.
  3. 03Use the ?.Invoke() null-conditional so raising an event with no listeners is safe.
  4. 04Pass data in the event (HealthChanged(current, max)) so observers do not need to query back into the subject.
  5. 05For game-wide events, consider a ScriptableObject event channel so scenes and prefabs can communicate without direct references.