delegate 가 생각나는 패턴
여러 객체가 등록해두고 이벤트 발생 시 자동으로 호출되는 구조면 옵저버 패턴
Subject(관찰대상)와 observer(관찰자)가 있으며
Subject는 observer를 모아두고 특정 조건이 발생했을때 observer들 한테 특정 행동을 하라고 지시한다
1. 인터페이스를 만든다 (Observer가 가져야할 콜백 메서드 정의)
Subject에서 행동을 하라고 지시했을때 Observer에서 어떤 행동을 할것인지 작성하기위해서
2. observer(관찰자) 클래스를 만든다
앞서 만든 인터페이스를 상속하고, 실제 행동인 해당 기능을 구현한다.
Awake로 구독, OnDestroy로 반드시 구독을 해제해준다 (순환참조 방지위해서 Destroy)
3. Subject(관찰대상) 를 만든다.
List<인터페이스>를 만들어서 관찰자들의 인터페이스 정보를 저장해둔다.
특정 조건이 만족하면 foreach로 List를 순회하며 인터페이스에서 구현했던 메소드를 호출해준다 (콜백 호출)
Call Back : 어떤 이벤트나 동작이 일어난 후 호출되는 함수
지금 코드는 Awake되면 자동으로 구독하는 구조인데 꼭 이렇게 안하고, 구독/알림구조라면 옵저버패턴임


왼쪽위의 TMP Text에 1초가 지날때마다 옵져버 패턴으로 갱신된다
추가 코드: delegate를 써서 Observer 패턴 구현
1.ITimeChange + UiTimeSet (인터페이스와 observer 코드)
//1. ITimeChange.cs 파일
public interface ITimeChange
{
public void PrintNowTime(float fTime); //시간 설정
}
//2. UiTimeSet.cs 파일
public class UiTimeSet : MonoBehaviour, ITimeChange
{
//UI에 시간을 넣기
[SerializeField] TextMeshProUGUI guiText; //TMP Text에 표시하기 위해서
[SerializeField] TimerUi timerUi; //어떤 관찰대상에서 값을 받아올것인지
public void PrintNowTime(float fTime)
{
guiText.text = fTime.ToString(); //TMP Text 값 수정
}
private void Awake()
{
timerUi.AddTimeChange(this); //구독
}
private void OnDisable()
{
timerUi.RemoveTimeChange(this); //구독 해제
}
}
2.TimerUi (Subject(관찰대상) 코드)
public class TimerUi : MonoBehaviour //Subject 클래스
{
//1초가 지날때마다 UI의 TMP Text가 변경, Interface는 OnTimeChange라는 것을 만들고
//인터페이스를 관리하는 클래스에서 1초가 지난시점에 이벤트를 발생시킴
//Observer(관찰자)들은 Awake시점에 해당 이벤트를 추가한다
private List<ITimeChange> _timeChangeList = new List<ITimeChange>(); //이벤트 목록
public void AddTimeChange(ITimeChange time) => _timeChangeList.Add(time); //관찰자들이 이벤트 추가할때 사용하는 메서드
public void RemoveTimeChange(ITimeChange time) => _timeChangeList.Remove(time); //이벤트 삭제 시 추가하는 메서드
private float currentTime = 0f; //현재 시간
private int previousSecond = 0; //이전 시간 (초)
private void Awake()
{
currentTime = 0f; //초기 시간 설정
}
private void Update() //1초마다 이벤트 보내기 위해서 사용
{
currentTime += Time.deltaTime;
int currentSecond = Mathf.FloorToInt(currentTime); //소수점 이하 무조건 버린 숫자
if(currentSecond > previousSecond) //1초마다 체크
{
Debug.Log(currentSecond + "초 경과");
previousSecond = currentSecond;
SetTimerInvoke(); //1초가 지날때마다 Observer들에게 알려줌
}
}
private void SetTimerInvoke() //모든 Observer들에게 값을 넣어줌
{
foreach(ITimeChange item in _timeChangeList)
{
int currentSecond = Mathf.FloorToInt(currentTime);
item.PrintNowTime(currentSecond);
}
}
}
객체간 상태변화를 자동으로 동기화 해야하는 상황에 사용
코드간 결합도를 낮추고, 확장성 높은 이벤트 기반 시스템 구성 가능
예시)
옵저버 패턴은 이런경우 발행자(Publisher)가 변화를 통보하고, 여러 구독자가 자동으로 반응

옵져버 패턴은 아니지만 비슷한 기능인데 중앙에서 관리한다는 점이 달라 여기에 정리.
지금은 이벤트버스가 있다는거만 알자 옵져버 패턴과 비슷하지만 옵져버패턴은 1:N으로 연결되고 발행자가 구독자를 알아야한다
하지만 이벤트 버스는 중앙의 EventBus라는 허브? 가 존재하고 발행자가 EventBus에 이벤트 발생을 알리면 버스가 구독한 애들한테 알아서 전달한다고 한다 (발행자와 구독자가 서로 몰라도됨)
키워드: 옵저버, 옵져버, observer