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