Pausing Observer Notifications

Is it possible to temporarily pause notifications to specific observers?

Yes, there are several ways to implement notification pausing. Let's explore a few approaches, starting with the simplest and moving to more sophisticated solutions.

Boolean Flag Approach

The simplest approach is to add a boolean flag to control whether notifications are active:

class Player {
public:
  using DamageDelegate = std::function<void(
    int NewHealth)>;

  void SetDelegate(DamageDelegate D) {
    OnDamage = D;
  }

  void PauseNotifications() {
    NotificationsPaused = true;
  }

  void ResumeNotifications() {
    NotificationsPaused = false;
  }

  void TakeDamage(int Damage) {
    Health -= Damage;
    if (!NotificationsPaused && OnDamage) {  
      OnDamage(Health);                      
    }                                        
  }

private:
  DamageDelegate OnDamage;
  bool NotificationsPaused{false};
  int Health{100};
};

RAII Pause Guard

A more robust approach uses RAII to ensure notifications are always resumed:

class Player {
 public:
  class NotificationGuard {
   public:
    NotificationGuard(Player& P) : Subject{P} {
      Subject.PauseNotifications();
    }
    ~NotificationGuard() {
      Subject.ResumeNotifications();
    }

   private:
    Player& Subject;
  };

  // ... rest of Player implementation
};

void GameLogic() {
  Player P;

  // Notifications active
  P.TakeDamage(10);

  {
    // Notifications paused
    Player::NotificationGuard Guard{P};  
    P.TakeDamage(20);
    // Even if we throw an exception here,
    // notifications will resume
  }  // Guard destroyed, notifications resume

  P.TakeDamage(30);
}

Selective Pausing

For more granular control, we can track pause state per observer:

class Player {
public:
  using DamageDelegate = std::function<void(
    int NewHealth)>;

  int AddDelegate(DamageDelegate D) {
    Observers[NextKey] = {D, false};
    return NextKey++;
  }

  void PauseObserver(int Key) {
    if (
      auto It = Observers.find(Key);
      It != Observers.end()
    ) {
      It->second.Paused = true;
    }
  }

  void ResumeObserver(int Key) {
    if (
      auto It = Observers.find(Key);
      It != Observers.end()
    ) {
      It->second.Paused = false;
    }
  }

  void TakeDamage(int Damage) {
    Health -= Damage;
    for (auto& [Key, Observer] : Observers) {
      if (!Observer.Paused) {
        Observer.Callback(Health);         
      }
    }
  }

private:
  struct Observer {
    DamageDelegate Callback;
    bool Paused;
  };

  std::unordered_map<int, Observer> Observers;
  int NextKey{0};
  int Health{100};
};

Choose the approach that best matches your needs:

  • Simple boolean flag for basic pause/resume
  • RAII guard for exception-safe pausing
  • Per-observer tracking for fine-grained control

Remember that paused observers still consume memory, so if you need to permanently disable an observer, you should remove it completely rather than just pausing it.

Delegates and the Observer Pattern

An overview of the options we have for building flexible notification systems between game components

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Why Use Delegates?
Why do we need to use delegates instead of just calling functions directly?
Delegate Performance Impact
How does the performance of delegates compare to direct function calls?
Handling Multiple Event Types
Can I have an observer observe multiple different types of events from the same subject?
std::function vs Function Pointer Performance
What's the overhead of using std::function compared to raw function pointers?
Smart Pointers with Observers
Can I use smart pointers to automatically manage observer registration/unregistration?
Observer Pattern Without Dynamic Allocation
Is it possible to implement the observer pattern without dynamic memory allocation?
Or Ask your Own Question
Get an immediate answer to your specific question using our AI assistant