Skip to content

Observer Pattern

Aprius edited this page Nov 8, 2024 · 4 revisions

What

Wikipedia's defintion of the observer pattern:

The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

So the basic idea is that you should use the observer pattern when you need many objects to receive an update when another object changes. The observer pattern is actually the communication backbone of countless programs and app frameworks, so pay attention.

One example is when you have achievements in your game. This might be difficult to implement if you have several achievements each unlocked by a different behavior. But it's much easier to implement if you know the observer pattern.

Usage

1, Create an Observer for a specific purpose by extending one of the following interfaces

  • IObserver
  • IObserver<T>
  • IObserver<T0, T1>
  • IObserver<T0, T1, T2>

Implement specific handling logic inside the OnNotify method

using Pancake.Pattern;

public class KillEnemyObserver : IObserver
{
    private readonly int _threshold;
    private readonly string _id;

    public KillEnemyObserver(string id, int threshold)
    {
        _id = id;
        _threshold = threshold;
    }

    public void OnNotify()
    {
        if (UserData.TotalEnemyKilled >= _threshold && !UserData.IsAchievementUnlocked(_id))
        {
            Debug.LogWarning($"You Killed {_threshold} Enemies");
            UserData.UnlockAchievement(_id);
        }
    }
}

2, Create an Publisher bằng cách kế thừa từ một trong những class abstract sau:

  • Publisher
  • Publisher<T>
  • Publisher<T0, T1>
  • Publisher<T0, T1, T2>

These classes all have a protected Notify method that will iterate over all observers and notice them. You can only call this method from inside a class that inherits from Publisher following the encapsulation principle.

using Pancake.Pattern;

public class KillAchievementPublisher : Publisher
{
    public void CheckAndNotify() { Notify(); }
}

3,

using Pancake.Pattern;

public class Demo : MonoBehaviour
{
    private readonly KillAchievementPublisher _publisher = new();
    private readonly KillEnemyObserver _kill10Enemy = new("kill_10_enemy", 10);
    private readonly KillEnemyObserver _kill100Enemy = new("kill_100_enemy", 100);
    private readonly KillEnemyObserver _kill1000Enemy = new("kill_1000_enemy", 1000);

    private void OnEnable()
    {
        _publisher.AddObserver(_kill10Enemy);
        _publisher.AddObserver(_kill100Enemy);
        _publisher.AddObserver(_kill1000Enemy);
    }

    private void OnDisable()
    {
        _publisher.RemoveObserver(_kill10Enemy);
        _publisher.RemoveObserver(_kill100Enemy);
        _publisher.RemoveObserver(_kill1000Enemy);
    }
}

Now every time you kill an enemy you can increment your count counter and call your publisher's CheckAndNotify

        UserData.TotalEnemyKilled ++;
        Debug.LogWarning("TotalEnemyKilled:" + UserData.TotalEnemyKilled);
        _publisher.CheckAndNotify();
Clone this wiki locally