Why Does Redo Exist?
At first glance, a Redo operation might seem identical to calling Execute() again — but in practice, this is not always the case.
Execute vs Redo
In many simple scenarios, redoing an action can safely call Execute() again. However, in more complex systems, especially those involving runtime state and object lifecycles, this can lead to unintended behavior.
The Problem
Consider a command that spawns an object and stores a reference to it:
public void Execute(Action executedCallback)
{
_spawnedObject = Object.Instantiate(_prefab);
_objects.Add(_spawnedObject);
executedCallback?.Invoke();
}If you implement Redo() by simply calling Execute() again:
public void Redo()
{
Execute(null);
}You will:
- Spawn a new object
- Lose the original reference
- Potentially create duplicates
- Break consistency in systems that rely on stable references
The Correct Approach
Instead, Redo() should restore the previous state using the existing data, not recreate it.
public void Undo()
{
_spawnedObject.SetActive(false);
}
public void Redo()
{
_spawnedObject.SetActive(true);
}This ensures:
- The same object instance is reused
- References remain valid
- No duplicate objects are created
Why This Matters
This pattern is especially important in:
- Runtime editors
- Level editors
- Systems that rely on stable object references
- Deterministic simulations
By separating Execute() and Redo(), you maintain full control over object lifecycle and state restoration.
Best Practice
Use Execute() for initial creation or first-time execution Use Redo() for restoring a previously undone state If your command does not rely on persistent references, it is perfectly fine to implement:
public void Redo()
{
Execute(null);
}Summary
Execute() ≠ Redo()
Execute() may create new state.
Redo() should restore existing state.
Only reuse Execute() in Redo() when it is safe to do so.
This design ensures your commands remain predictable, stable, and safe for undo/redo workflows — even in complex runtime systems 🚀