0

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?

1
  • 2
    "particularly important with static events to unsubscribe" - so, C# events are exactly the same as the Observer pattern, it's just a bit of syntactic sugar, so it looks a little different at first glance. When you += an event, a reference to the object that houses the handler method gets internally added to the underlying delegate, similar to how AddObserver works. So having a static event on some class is like having a global long-lived Subject class, except in this variation the Notify() method (in this case called .Invoke()) gets triggered by some external object. Apr 25, 2023 at 13:46

1 Answer 1

2

which is the usual approach to implementing the observer pattern without explicitly adding the observers to the subject instance?

One approach I could think of to implementing the observer pattern without the subject class keeping track of its observers is to use a message passing system or an event bus. This involves creating a central system that allows different objects to communicate without directly referencing each other. It allows for a more dynamic observer set, as new observers can be added or removed at runtime without the need to modify the subject class.

If static events are generally used in this way, are there any downsides to it?

While your approach of using static events to implement the observer pattern is valid in my opinion, there are indeed potential issues. One is that static events can be harder to manage and may lead to memory leaks if not properly handled. Since static events are not tied to a particular instance, they can be accessed from anywhere in the code, making it harder to track who is subscribing or unsubscribing. Another thing to consider is that static events can be prone to race conditions or other synchronization issues in multi-threaded environments.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.