이벤트 기반 프로그래밍 - 옵저버 패턴, 이벤트 버스 패턴
- 효율적으로 프로그램이 실행되도록 설계할 수 있는 패턴
- Pub- Sub 패턴 이라고도함 (발행 - 구독 패턴)
발행자 1 - 구독자 1 : 함수 직접 호출 → 이 함수에 반응해야하는 함수가 늘어나면 일일이 호출해야함
발행자 1 - 구독자 다수 : 옵저버 패턴 사용 → 여러개의 함수에서 특정 함수를 호출하고싶으면 특정 함수를 모든 델리게이트에 등록해야함
발행자 다수 - 구독자 다수 : 이벤트 버스 패턴 사용 → 등록과 호출을 하나의 스크립트에서 전담
옵저버 패턴
- 발행자 1 - 구독자 n 의 관계
- 이벤트 발생시, 발행자가 이벤트 발생을 알리고 구독자들이 행동하는 패턴
- 델리게이트를 통해 구현 가능
- public event Action<> 의 형태로 사용하는것이 옵저버 패턴
public class CharacterBuffs : MonoBehaviour
{
public Dictionary<int, Coroutine> nowBuffs = new Dictionary<int, Coroutine>();
//이벤트 발행(발행자)
public UnityAction<BuffData> onAddBuff;
//버프를 받을때 호출
public void AddBuff(BuffData addedBuff)
{
nowBuffs.Add(addedBuff.buffId, StartCoroutine(MaintainBuff(addedBuff)));
//이벤트 호출
onAddBuff?.Invoke(addedBuff);
}
}
public class BuffListUI : MonoBehaviour
{
public GameObject buffInfoUI;
private Dictionary<int, GameObject> buffInfos = new Dictionary<int, GameObject>();
private void Start()
{
//이벤트 등록(구독자)
CharacterManager.Instance.Player.buffs.onAddBuff += AddBuffInfo;
}
//이벤트 발생시 작동할 함수
public void AddBuffInfo(BuffData buff)
{
if (buffInfos.ContainsKey(buff.buffId))
{
Destroy(buffInfos[buff.buffId]);
RemoveKey(buff.buffId);
}
buffInfos.Add(buff.buffId, Instantiate(buffInfoUI, transform));
buffInfos[buff.buffId].GetComponent<BuffInfoUI>().SetUp(buff);
buffInfos[buff.buffId].GetComponent<BuffInfoUI>().onDestroy += RemoveKey;
}
private void RemoveKey(int buffId)
{
buffInfos.Remove(buffId);
}
}
이런식으로 event 를 등록, 호출하는것을 옵저버 패턴이라고 함
이벤트 버스 패턴
- 발행자 n - 구독자 n 의 관계
- 이벤트 구현시 발행자와 구독자 사이의 의존성을 만들지 않음
더보기
이벤트 버스 코드
public enum EventName
{
Event1,
Event2
}
public class EventManager : MonoBehaviour
{
#region sington
private static EventManager instance;
public static EventManager Instance
{
get { return instance; }
}
public static bool InstanceExist { get { return instance != null; } }
private void Awake()
{
if(InstanceExist)
{
Destroy(gameObject);
return;
}
instance = this;
}
private void OnDestroy()
{
instance = null;
}
#endregion
private Dictionary<EventName, Action> events = new Dictionary<EventName, Action>();
public void SubEvent(EventName name, Action action)
{
if(events.TryGetValue(name, out Action thisEvent))
{
thisEvent += action;
}
else
{
thisEvent = action;
events.Add(name, thisEvent);
}
}
public void DeSubEvent(EventName name, Action action)
{
if(events.TryGetValue(name, out Action thisEvent))
{
thisEvent -= action;
}
}
public void Publish(EventName name)
{
if(events.TryGetValue(name, out Action thisEvent))
{
thisEvent.Invoke();
}
}
}
public class Listoner : MonoBehaviour
{
private void OnEnable()
{
EventManager.Instance.SubEvent(EventName.Event1, DoSomething);
}
private void OnDisable()
{
EventManager.Instance.DeSubEvent(EventName.Event1, DoSomething);
}
public void DoSomething()
{
Debug.Log("이벤트 발생 확인");
}
}
public class Publisher : MonoBehaviour
{
private void Update()
{
if(Input.GetKeyDown(KeyCode.A))
{
EventManager.Instance.Publish(EventName.Event1);
}
}
}
주의사항
- 이벤트 버스에 대한 의존성이 높아질 수 있음
- 복잡해질경우 관리가 어려울 수 있음
※ 옵저버 패턴과 이벤트 버스 패턴
- 상술했듯, 이 둘을 묶어서 Pub - Sub 패턴 이라고도 함
- 옵저버패턴은 발행자에게 이벤트를 직접 등록
- 이벤트 버스 패턴은 버스에 이벤트를 구독하고, 버스를 통해 이벤트를 발행
- 이 과정을 통해 발행자와 구독자간의 의존성이 사라짐
명령패턴
- 행동을 객체로 만들어 재사용
- 기록, 취소 병렬처리를 쉽게 하기 위해 사용됨
- 객체화를 통해 복잡한 작업을 순차적으로 처리 or 되돌림
구현
- 로깅
- 행동에 로그를 남길때 사용
- ICommand 인터페이스를 사용, 로그를 남기는 메서드를 강제 구현함
- 캐릭터 컨트롤러등에 커멘드 로거 연결, 리스트에 로그를 남김
- 되돌리기 시스템
- ICommand 인터페이스에 실행, 역실행 메서드 강제 구현
- ICommand인터페이스를 스택에 쌓은 뒤, 되돌리기 실행시 스택을 꺼내 역실행 메서드 실행
파사드 패턴 (Facade)
- 작은 클래스들의 객체를 가지고 있는 큰 클래스 생성, 큰 클래스가 작은 클래스의 문지기 역할을 함
- 작은 클래스에 명령이 들어올경우, 큰 클래스를 통해 전달함
public class Player : MonoBehaviour
{
public PlayerController controller;
public PlayerCondition condition;
public Equipment equip;
public CharacterBuffs buffs;
public ItemData itemData;
public UnityAction addItem;
public Transform dropPosition;
private void Awake()
{
CharacterManager.Instance.Player = this;
controller = GetComponent<PlayerController>();
condition = GetComponent<PlayerCondition>();
equip = GetComponent<Equipment>();
buffs = GetComponent<CharacterBuffs>();
}
}
※ 숙련주차 강의의 Player 클래스에서 파사드 패턴이 활용됨, 해당 클래스는 싱글톤 클래스인 CharacterManager 에서 연결되어, Player를 통해 하위 클래스들에게 명령을 전달함
'내일배움캠프 > TIL' 카테고리의 다른 글
유니티 숙련주차 팀 프로젝트 - 제작 시스템 추가 (0) | 2024.11.01 |
---|---|
팀프로젝트 제작 시작 - 크래프팅 시스템 (0) | 2024.10.31 |
유니티 숙련주차 개인프로젝트 마무리? (0) | 2024.10.29 |
1차 디자인패턴 특강 정리 (0) | 2024.10.28 |
내일배움캠프 28일차 TIL - 시야각 내의 오브젝트 판단하기 (0) | 2024.10.25 |