Naming Events and Handlers

Source

There are many ways in which to name events and it’s handler functions. Lately I've found one that suits me.

Let me give you some options so you can choose which one works best for you.

First, let’s define our Character class that has a health parameter. This class will fire events when health decreases. Another class, named CharacterAnimator, will consume this event and handle it accordingly.

//Handles main character logic
public class Character
{
public Action onHealthDecrease;
public int health;
   public CharacterAnimator animator;
   public void Init()
{
animator.Init(this);
}
   public void DecreaseHealth(int amount)
{
health -= amount;
if(onHealthDecrease != null)onHealthDecrease();
}
}

Let’s take a look at some of the options ahead.

Option A

//Handles character animation
public class CharacterAnimator
{
  public void Init(Character character) 
{
character.onHealthDecrease += OnHealthDecrease;
}
  public void OnHealthDecrease()
{
//play "hurt" animation
}
}

This is probably one of the most common. You use the onSomethingHappens format to name both the event and it’s handlers. I think it’s OK, but I don’t like the fact that both have the same name. Also the fact that the function isn't named after an action also bothers me.

Option B

//Handles character animation
public class CharacterAnimator
{
  public void Init(Character character) 
{
character.onHealthDecrease += () => {Play("hurt");});
}
  public void Play(string animationName)
{
//play "hurt" animation
}
}

This option gets rid of the confusing name for the function seen on the last one. The function is named like any other, with the action it will perform. The main drawback is that just looking at the function you can’t tell right away that it handles an event.

Option C

//Handles character animation
public class CharacterAnimator
{
  public void Init(Character character) 
{
character.onHealthDecrease += HandleCharacterHealthDecrease;
}
  public void HandleCharacterHealthDecrease()
{
Play("hurt");
}
  public void Play(string animationName)
{
//play animationName
}
}

The third option is the one I’m currently using. It solves both issues the other two have.

First it states a clear name for the function with the action it will perform. Second it’s easy to spot this function while glancing through the code and tell that this is a function that handles an event.

Bonus: Interfaces

This also facilitates us to write interfaces for our code when it’s needed. In the case above we could simply have:

public inteface CharacterHealthChangeHandler
{
void HandleCharacterHealthDecrease();
void HandleCharacterHealthReachZero();
}

Now imagine we have another system similar to the animation one, but this time it handles audio.

//Handles character audio
public class CharacterAudio : CharacterHealthChangeHandler
{
  public void Init(Character character) 
{
character.onHealthDecrease += HandleCharacterHealthDecrease;
character.onHealthReachZero += HandleCharacterHealthReachZero;
}
  public void HandleCharacterHealthDecrease()
{
Play("hurt");
}
  public void HandleCharacterHealthReachZero()
{
Play("death");
}
  public void Play(string audioId)
{
//play audioId
}
}

Let’s update the CharacterAnimator as well.

//Handles character animation
public class CharacterAnimator : CharacterHealthChangeHandler
{
  public void Init(Character character) 
{
character.onHealthDecrease += HandleCharacterHealthDecrease;
character.onHealthReachZero+= HandleCharacterHealthReachZero;
}
  public void HandleCharacterHealthDecrease()
{
Play("hurt");
}
  public void HandleCharacterHealthReachZero()
{
Play("death");
}
  public void Play(string animationName)
{
//play animationName
}
}

To sum it up:

  • Events → “on” + Action
    Examples: onAttack, onSpawn, onMove
  • Event handler function → “Handle” + ClassName + Action
    Examples: HandleCharacterAttack, HandleCharacterSpawn, HandleCharacterMove
  • Event handler interface → ClassName + EventArea + “Handler”
    Examples: CharacterCombatHandler, CharacterLifeCycleHandler and CharacterMovementHandler

There are probably more ways of writing this kind of code. These are some of the options. Please feel free to take these and modify to your liking.