Observer Pattern

2025. 10. 21. 15:25·🧊Unity Basic/디자인패턴

옵저버 패턴 ( Observer Pattern )

배고픈 개발자가 패스트푸드점에 가서 햄버거를 주문했다고 가정한다.

주문을 마친 후 , 제일 먼저 떠오르는 질문은 " 내 주문은 언제 나오죠? "

배고픈 개발자는 그 답을 얻기 위해 카운터 근처를 서성인다.

조리대 쪽을 기웃거리며 , 직원이 봉투를 들 때마다 혹시 내 건가 싶어 고개를 빼보기도 한다.

하지만 이건 꽤 번거로운 일이다.

 

이 방식이 바로 Polling ( 폴링 ) 이다.

내 주문이 준비되었는지 스스로 계속 확인하는 방식을 말한다.

이건 매번 Update( ) 함수에서 "햄버거 다 됐나?" 를 체크하는 것과 같다.

주문이 아직인데도 계속 확인하니 , 사람도 피곤하고 시스템도 낭비가 생긴다.

 

그런데 요즘은 대부분의 매장에서 주문을 마치면 번호표나 진동벨을 준다.

혹은 화면에 주문번호가 뜨기도 한다.

햄버거가 완성되면 직원이 "OO번 주문 나왔습니다!" 하고 알리거나, 진동벨이 울려 배고픈 개발자에게 알려준다.

배고픈 개발자는 그제서야 카운터로 가서 햄버거를 받아온다.

이때 점원 또는 조리 시스템이 바로 Subject ( 주체 ) 이고 , 배고픈 개발자 손님은 Observer ( 감시자 ) 이다.

손님이 계속 물어보는 대신에 점원이 "이제 준비 끝났어요" 라고 Notify ( 알림 ) 신호를 보내면

손님 ( Observer ) 은 그제서야 Update ( 응답 ) 해서 햄버거를 받으러 간다.

 

이게 바로 옵저버 패턴의 핵심 원리이다.

" 변화를 스스로 감지하려 하지 말고 , 변할 때 알려달라 "

 

게임에서도 같은 상황이 있다.

플레이어의 체력이 줄어들 때마다 UI 가 직접 계속 " 체력이 변했나?" 를 확인할 필요가 없다.

대신 플레이어 객체가 "체력이 변했어!" 라는 이벤트를 던지고

UI 나 사운드 시스템이 그 이벤트를 구독 ( Subscribe ) 하고 있다면 자동으로 반응할 수 있다.

 

 

정의

  • 한 객체의 상태 변화가 있을 때
    그 객체 ( Subject ) 를 관찰 ( Observe ) 하고 있는 다른 객체들 ( Observer ) 에게 자동으로 알림을 보내는 구조이다
  • A 객체가 B 객체를 직접 호출하지 않아도 , A 의 변화가 B 에게 전달되도록 만드는 것
    결합도를 낮추는 것이 핵심이다. 
역할 설명
Subject ( 발행자 / Publisher ) 상태 변화를 감지하고 , Observer 들에게 알림을 전달한다
Observer ( 구독자 / Subscriber ) Subject 에 등록되어 있다가 , 변화가 생기면 알림을 받아 동작을 수행한다
  1. Observer들은 Subject.Subscribe( ) 로 구독 등록
  2. Subject 의 내부 상태가 변한다
  3. Subject 는 Notify( ) 를 호출해 모든 구독자에게 알린다
  4. Observer 들이 각자 정의된 행동 ( OnNotify( ) 등 ) 을 실행한다

 

 

예시 코드

using System;
using System.Collections.Generic;

// Subject
public class Player
{
    private List<IObserver> observers = new List<IObserver>();
    public int HP { get; private set; } = 100;

    public void Subscribe(IObserver observer) => observers.Add(observer);
    public void Unsubscribe(IObserver observer) => observers.Remove(observer);

    public void TakeDamage(int dmg)
    {
        HP -= dmg;
        Notify();
    }

    private void Notify()
    {
        foreach (var obs in observers)
            obs.OnNotify(HP);
    }
}

// Observer 인터페이스
public interface IObserver
{
    void OnNotify(int newHP);
}

// 실제 Observer
public class UI_HPBar : IObserver
{
    public void OnNotify(int newHP)
    {
        Console.WriteLine($"💖 HP 갱신됨: {newHP}");
    }
}

 

 

유니티에서의 활용

유니티에서는 옵저버 패턴이 다음과 같은 경우에 자주 사용한다.

  1. 게임 이벤트 시스템
    플레이어의 HP , 점수 , 경험치 등이 바뀔 때 UI 자동 갱신
    HPManager 가 발행자 , HP_UI 가 구독자 역할
  2. UI 업데이트
    인벤토리 , 미션 목록 , 스코어 보드 등
    데이터 변화에 따라 UI 갱신 ( UIManager 가 옵저버 )
  3. 퀘스트 / 미션 시스템
    몬스터 처치 시 퀘스트 달성 등
    MonsterManager 가 몬스터 처치 이벤트 발행
    QuestManager 가 그 이벤트를 구독한다
  4. ScriptableObject 기반 이벤트 ( UnityEvent 대체 )
    유니티에서는 종종 ScriptableObject 를 이용해 옵저버 패턴을 구현하기도 한다
    ( EventChannel 패턴이라고도 부른다 )

 

장점과 단점

장점 단점
결합도 감소 ( 객체 간 독립성 확보 ) Observer 가 많으면 관리가 복잡해진다
유지보스 용이 ( Subject 를 바꿔도 구독자 영향이 적다 ) 디버깅이 어려워진다 ( 어디서 Notify 됐는지 추적 필요 )
코드 재사용성 높다 순서 의존 문제 가능 ( 등록 순서 등 )

 

 

 

주의할 점

1. 구독 ( Subscribe ) 후 , 반드시 해제 ( Unsubscribe ) 해야 한다

옵저버 패턴의 가장 흔한 버그는 이벤트 구독 해제 누락이다.

오브젝트가 Destroy 되었는데도 불구하고 구독이 유지되면 

이벤트 발생 시 NullReferenceException 이 터지거나

GC 대상이 되지 않아 메모리 누수가 생긴다.

private void OnEnable()
{
    player.OnHpChanged += UpdateUI;
}

private void OnDisable()
{
    player.OnHpChanged -= UpdateUI; // 꼭 필요하다
}
  • OnEnable 에서 구독했으면 OnDisable 에서 반드시 해제
  • Awake 에서 구독했으면 OnDestroy 에서 해제

 

 

2. 이벤트 순서 / 실행 타이밍 주의

옵저버가 여러 개일 때 Notify( ) 가 호출되는 시점에 누가 먼저 반응할지 예측이 어렵다

  • HP 감소 이벤트 → UI 먼저 업데이트 or 게임오버 처리 먼저 실행
  • 순서가 중요하다면 우선순위 관리 또는 이벤트 큐 시스템이 필요하다

중요한 이벤트라면 EventManager 나 Priority Queue 를 사용해서 통제

 

 

 

3. 이벤트 중복 등록 ( Double Subscription ) 방지

코드 구조상 OnEnable 이 여러 번 호출될 수 있다.

(예시  : SetActive(true) 반복 등 )

private void OnEnable()
{
    player.OnHpChanged += UpdateUI;  // 중복으로 등록될 수 있다
}

이벤트가 중복 등록되면 한 번 HP가 바뀔 때마다 UI 가 여러 번 갱신된다

private void OnEnable()
{
    player.OnHpChanged -= UpdateUI; // 먼저 제거
    player.OnHpChanged += UpdateUI; // 다시 등록
}

이렇게 작성하면 중복 방지 가능하다.

 

 

 

4. 씬 전환시 구독 관계 초기화 주의

  • 씬이 전환되면 대부분의 MonoBehaviour 는 Destroy 된다.
  • 하지만 static 이벤트나 DontDestroyOnLoad 객체는 그대로 남는다

구독한 객체는 사라졌는데 , 이벤트 발행자는 남아 있으면 이전 씬 객체 참조 문제로 크래시가 난다.

SceneManager.SceneLoaded 이벤트로 초기화 타이밍을 제어

또는 EventManager.ClearALL( ) 같은 전역 해제 함수 추가

 

 

 

정리

옵저버 패턴은 결합도 줄이는 강력한 도구이다

하지만 구독 해제 / 순서 제어 / 남용 방지를 놓치면 디버깅 지옥이 된다.

'🧊Unity Basic > 디자인패턴' 카테고리의 다른 글

MVC 패턴  (0) 2025.11.10
Adapter Pattern 핵심 코드  (0) 2025.10.24
Singleton 과 Generic  (0) 2025.10.21
Singleton Pattern  (0) 2025.10.20
Adapter Pattern  (0) 2025.10.19
'🧊Unity Basic/디자인패턴' 카테고리의 다른 글
  • MVC 패턴
  • Adapter Pattern 핵심 코드
  • Singleton 과 Generic
  • Singleton Pattern
DevHoChan
DevHoChan
맨땅에서 시작하는 코딩 도전
  • DevHoChan
    Debugging Life
    DevHoChan
  • 전체
    오늘
    어제
    • 분류 전체보기 (374)
      • 🕹️Game Life (1)
      • 🖥️Computer Science (5)
      • 📖TIL (141)
        • 🔥Projects (16)
        • 💡DevTips (5)
        • 🤔발생한 문제와 해결 (5)
        • 🔮Unity Graphics (5)
        • 🎤Interview (3)
        • ✅CodingTest (9)
      • 🚀Game Release (4)
      • 🧊Unity Basic (58)
        • 📌용어 사전 (1)
        • 에디터&인터페이스 (3)
        • 디버그 (1)
        • 라이프사이클 (4)
        • 게임오브젝트 (4)
        • 프리팹 (1)
        • 오브젝트풀링 (4)
        • 애트리뷰트 (2)
        • 트랜스폼 (4)
        • 물리&충돌 (1)
        • 프레임&델타타임 (4)
        • 코루틴&이벤트 (7)
        • 수학&보정함수 (3)
        • 디자인패턴 (9)
        • UGUI (3)
        • 벡터 ( Vector ) (3)
        • 씬 ( Scene ) (2)
        • 데이터 관리 (2)
      • ⭐C Sharp (99)
        • 📌용어 사전 (1)
        • 📌문법 사전 (6)
        • 메모리 관리 (3)
        • 00. 문법 (17)
        • 01. 변수 (3)
        • 02. 자료형 (2)
        • 03. 연산자 (6)
        • 04. 조건문 (2)
        • 05. 반복문 (2)
        • 06. 배열 (3)
        • 07. 메서드(함수) (7)
        • 08. 열거형 (3)
        • 09. 구조체 (2)
        • 10. 참조 (2)
        • 11. 객체 지향 (11)
        • 12. 델리게이트 (3)
        • 13. 디자인 패턴 (7)
        • 14. LINQ (1)
        • 📂▼자료구조 (2)
        • 15-1. 제네릭 (3)
        • 15-2. 배열 (4)
        • 15-3. 리스트 (2)
        • 15-4. 스택과 큐 (2)
        • 15-5. 딕셔너리 해시테이블 (2)
        • 15-6. 트리와 그래프 (3)
      • 📊Algorithm (16)
        • BigO (2)
        • 정렬 (4)
        • 셔플 (2)
        • 탐색 (6)
        • 최적화 (1)
      • 📝Game Design (16)
      • 🤖​AI Tools (12)
        • AI 리뷰 분석 (6)
        • Player2 (0)
        • 3D 모델링 (1)
        • 2D 스프라이트 (0)
        • 이미지 (2)
        • 사운드 (1)
        • 동영상 (1)
        • 문서 (1)
      • 🌍Network (6)
      • 🌱Github (11)
        • 기본 개념 (7)
        • 명령어 (1)
        • 도구 활용 (1)
      • ⚙️Visual Studio (5)
        • 🔧설치 및 환경설정 (2)
        • ⌨️HotKey (1)
        • 🚨디버깅 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    csharp
    OOP
    메모리관리
    게임기획
    게임디자인
    부트캠프
    유니티
    자료형
    c#
    GitHub
    til
    unity
    gamedesign
    디자인패턴
    CodingTest
    자료구조
    algorithm
    기획
    문법
    객체지향
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
DevHoChan
Observer Pattern
상단으로

티스토리툴바