옵저버 패턴
옵저버 패턴(Observer Pattern)은 정말 널리 쓰이는 디자인 패턴 중 하나. 주체(Subject)와 옵저버(Observer)가 상호작용하면서 상태 변화를 전달하는 방식은 특히 이벤트 중심의 시스템에서 효과적. 트위터나 소셜 네트워크의 로직처럼 실시간 업데이트가 필요한 상황에서 딱 들어맞음..
예를 들어, 트위터에서는:
주체(Subject): 특정 사용자가 게시글을 작성하거나 프로필을 업데이트할 때.
옵저버(Observer): 팔로워들이 주체의 게시글이나 업데이트를 바로 볼 수 있도록 알림을 받는 구조.
MVC 패턴에서도:
View(옵저버)는 Model(주체)를 관찰하다가, 데이터가 바뀌면 이를 반영해 화면을 갱신하는 방식으로 동작.
실제로 유니티에서도 이벤트 기반 구조를 구현할 때 옵저버 패턴을 적용할 수 있음. 예를 들면, 게임 내 점수나 체력 변화를 여러 UI 요소에 동기화시킬 때 사용 가능.
주체(Subject): HealthManager
using System;
using System.Collections.Generic;
using UnityEngine;
public class HealthManager : MonoBehaviour
{
public int Health { get; private set; } = 100; // 초기 체력
private List<IHealthObserver> observers = new List<IHealthObserver>();
public void RegisterObserver(IHealthObserver observer)
{
if (!observers.Contains(observer))
observers.Add(observer);
}
public void UnregisterObserver(IHealthObserver observer)
{
if (observers.Contains(observer))
observers.Remove(observer);
}
public void TakeDamage(int damage)
{
Health = Mathf.Max(Health - damage, 0);
NotifyObservers();
}
private void NotifyObservers()
{
foreach (var observer in observers)
{
observer.OnHealthChanged(Health);
}
}
}
// UNITY EVENT로 제작 시
using UnityEngine;
using UnityEngine.Events;
public class HealthManager : MonoBehaviour
{
public UnityEvent<int> OnHealthChanged = new UnityEvent<int>();
public int Health { get; private set; } = 100;
public void TakeDamage(int damage)
{
Health = Mathf.Max(Health - damage, 0);
OnHealthChanged.Invoke(Health); // 이벤트 호출
}
}
옵저버(Observer) 인터페이스
public interface IHealthObserver
{
void OnHealthChanged(int newHealth);
}
옵저버: HealthBar
using UnityEngine;
using UnityEngine.UI;
public class HealthBar : MonoBehaviour, IHealthObserver
{
[SerializeField] private Slider healthSlider;
private void Start()
{
// HealthManager를 찾아 등록
HealthManager healthManager = FindObjectOfType<HealthManager>();
if (healthManager != null)
{
healthManager.RegisterObserver(this);
}
}
public void OnHealthChanged(int newHealth)
{
healthSlider.value = newHealth / 100f; // 슬라이더 값 업데이트
}
}
// UNTIY EVENT로 제작시
using UnityEngine;
using UnityEngine.UI;
public class HealthBar : MonoBehaviour
{
[SerializeField] private Slider healthSlider;
private void Start()
{
HealthManager healthManager = FindObjectOfType<HealthManager>();
if (healthManager != null)
{
healthManager.OnHealthChanged.AddListener(UpdateHealthBar);
}
}
private void UpdateHealthBar(int newHealth)
{
healthSlider.value = newHealth / 100f;
}
}
옵저버: HealthText
using UnityEngine;
using UnityEngine.UI;
public class HealthText : MonoBehaviour, IHealthObserver
{
[SerializeField] private Text healthText;
private void Start()
{
HealthManager healthManager = FindObjectOfType<HealthManager>();
if (healthManager != null)
{
healthManager.RegisterObserver(this);
}
}
public void OnHealthChanged(int newHealth)
{
healthText.text = $"Health: {newHealth}";
}
}
// UNITY EVENT로 제작시
using UnityEngine;
using UnityEngine.UI;
public class HealthText : MonoBehaviour
{
[SerializeField] private Text healthText;
private void Start()
{
HealthManager healthManager = FindObjectOfType<HealthManager>();
if (healthManager != null)
{
healthManager.OnHealthChanged.AddListener(UpdateHealthText);
}
}
private void UpdateHealthText(int newHealth)
{
healthText.text = $"Health: {newHealth}";
}
}