Delegates and the Observer Pattern

Pausing Observer Notifications

Is it possible to temporarily pause notifications to specific observers?

Abstract art representing programming

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.

Answers to questions are automatically generated and may not have been reviewed.

sdl2-promo.jpg
Part of the course:

Game Dev with SDL2

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

Free, unlimited access

This course includes:

  • 53 Lessons
  • 100+ Code Samples
  • 91% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved