Advertisement

Observer patterns using static events

Started by April 25, 2023 08:22 AM
1 comment, last by Aressera 1 year, 7 months ago

I'm working on a game prototype: I have a Cell class which, given a mouse click on its collider, can raise an event that should be listened in two different modules: Camera and UI.

The Observer pattern implementation that I generally use follows this diagram:

enter image description here

But in this case it seems too tight and I don't see a simple way of adding such diverse observers explicitly to the Subject instance. So I tried to find a way to use the Observer pattern without the subject class keeping track of its observers, and the solution I found out is creating a C# static event raised from the Cell class:

public abstract class Cell : MonoBehaviour {

    public delegate void CellClikedHandler(Cell cell);
    public static event CellClikedHandler CellCliked;
    
    // ... 

    private void OnMouseDown() {
        CellCliked?.Invoke(this);
    }
}

public class ShowHideUI : MonoBehaviour {

    private void Awake() {
        Cell.CellCliked += ChangeUIVisibility;
    }

    public void ChangeUIVisibility(Cell cell) {
        //...
    }
}

public class CloseUpCamera : MonoBehaviour {

    private void Awake() {
        Cell.CellCliked += FocusCameraOnCell;
    }

    private void FocusCameraOnCell(Cell cell) {
        //...
    }
}

I have it currently working this way, but it doesn't feel right. I read here that it's particularly important with static events to unsubscribe so that instances don't get rooted, but I'm not sure of any further implications.

So I was wondering: which is the usual approach to implementing the observer pattern without explicitly adding the observers to the subject instance? If static events are generally used in this way, are there any downsides to it?

inmaculada said:
which is the usual approach to implementing the observer pattern without explicitly adding the observers to the subject instance? If static events are generally used in this way, are there any downsides to it?

How else would object A know to notify object B unless somehow B is associated with A? There's no way to get around it. What you have done by putting the delegate in a static variable is a hack that will break as soon as you need to have two instances of object A that each notify objects B and C respectively. (i.e. imagine you have a Button class that is used in two different places, and in each place needs to notify a different delegate when it is pressed).

The right solution is to make the CellClicked variable an instance variable instead of static, and to pass the delegate function into each Cell instance manually. This is how my GUI system works, and I have used it to create many complex interfaces in professional-quality software. If you have a large number of Cell objects that all use the same delegate, then it would be better to wrap those in a Table object that has a single delegate which is used for all cells.

This topic is closed to new replies.

Advertisement