Delegates and the Observer Pattern

Handling Multiple Event Types

Can I have an observer observe multiple different types of events from the same subject?

Abstract art representing programming

Yes, a single observer can handle multiple event types from the same subject. There are several ways to implement this, each with its own advantages. Let's explore the main approaches.

Multiple Delegate Properties

The simplest approach is to have separate delegates for each event type:

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

  void SetOnDamageDelegate(HealthDelegate D) {
    OnDamage = D;
  }
  void SetOnLevelUpDelegate(LevelDelegate D) {
    OnLevelUp = D;
  }

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

  void GainExperience(int Exp) {
    Experience += Exp;
    if (Experience >= 100) {
      Level++;
      if (OnLevelUp) OnLevelUp(Level);
      Experience -= 100;
    }
  }

 private:
  HealthDelegate OnDamage;
  LevelDelegate OnLevelUp;
  int Health{100};
  int Level{1};
  int Experience{0};
};

Event Objects

Another approach is to use a single delegate type but pass event objects that contain information about the event type:

enum class PlayerEventType { Damage, LevelUp };

struct PlayerEvent {
  PlayerEventType Type;
  int Value;
};

class Player {
public:
  using EventDelegate = std::function<
    void(const PlayerEvent&)>;

  void SetEventDelegate(EventDelegate D) {
    OnEvent = D;
  }

  void TakeDamage(int Damage) {
    Health -= Damage;
    if (OnEvent) {
      OnEvent({PlayerEventType::Damage, Health});
    }
  }

  void GainExperience(int Exp) {
    Experience += Exp;
    if (Experience >= 100) {
      Level++;
      if (OnEvent) {
        OnEvent({
          PlayerEventType::LevelUp, Level
        });
      }
      Experience -= 100;
    }
  }

private:
  EventDelegate OnEvent;
  int Health{100};
  int Level{1};
  int Experience{0};
};

The observer can then handle different event types:

void HandlePlayerEvent(const PlayerEvent& E) {
  switch (E.Type) {
    case PlayerEventType::Damage:
      std::cout << "Health changed to: "
        << E.Value << '\n';
      break;
    case PlayerEventType::LevelUp:
      std::cout << "Level up to: "
        << E.Value << '\n';
      break;
  }
}

Choose the approach that best fits your needs:

  • Multiple delegates are simpler but less flexible
  • Event objects are more complex but provide a unified interface
  • Event objects make it easier to add new event types later

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