디자인패턴

옵저버패턴

khkg12 2023. 11. 10. 15:32

옵저버패턴이란?

1대 다수의 관계를 갖는 패턴으로, 객체의 상태 변화를 관찰하는 관찰자들, 즉 옵저버들의 목록을 객체에 등록하여 상태 변화가 있을 때마다 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴이다. 라고 위키에 쓰여 있다. 즉 간단하게 말해서 1대 다수의 관계의 1의 상태변화를 등록된 모든 관찰자들에게 알리는 것이다.

 

예를 들어 일시정지 매니저와 일시정지에 적용될 객체들이 있다고 했을 때, 일시정지 매니저의 상태가 일시정지상태라면

이를 관찰하고 있는 모든 객체들 또한 일시정지라는 상황을 감지하고 그 기능을 수행하는 것이다.

 

사용 예시 코드

using UnityEngine;
using System;

public interface IPauseable // 일시정지 인터페이스
{
    void OnPauseRegister();    
}

public class Player : MonoBehaviour, IPauseable // 일시정지가 되어야할 클래스에 인터페이스 상속
{
    private void Awake()
    {
        Init();
    }

    public void Init()
    {
        OnPauseRegister();
    }

    public void OnPauseRegister() // 관찰자에 등록
    {
        PauseManager.instance.onPause += () => { enabled = false; }; 
        PauseManager.instance.onResume += () => { enabled = true; };
    }    
}

public class Monster : MonoBehaviour, IPauseable // player와 마찬가지
{
    private void Awake()
    {        
        Init();
    }

    public void Init()
    {
        OnPauseRegister();
    }

    public void OnPauseRegister()
    {
        PauseManager.instance.onPause += () => { enabled = false; };
        PauseManager.instance.onResume += () => { enabled = true; };
    }
}


public class PauseManager : MonoBehaviour
{
    public static PauseManager instance; // 옵저버 패턴은 1대다 관계이기 때문에 싱글톤으로 구현
    public event Action onPause; 
    public event Action onResume;

    public bool IsPaused
    {
        get => isPaused;
        set
        {
            isPaused = value;
            if (isPaused)
                Pause();
            else
                Resume();
        }
    }
    bool isPaused;

    private void Awake()
    {
        if (instance == null)
            instance = this;
        else
            Destroy(gameObject);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            IsPaused = !IsPaused; // 스페이스 바 클릭시 일시정지 및 해제
        }
    }

    public void ChangePauseState()
    {
        IsPaused = !IsPaused;
    }

    public void Pause()
    {
        onPause();
    }

    public void Resume()
    {
        onResume();
    }
}