오늘은 강의에서 Interface
와 delegate
, lambda
등의 개념이 나왔다.
중요한 개념인데 나는 많이 써보질 않아서 아직 헷갈리기도 하고 손에 안익는다...
그래서, 저 3개의 키워드를 다 같이 사용해보기 좋은 Observer Pattern
을 Unity로 구현해보면서 실습을 해보려고 했다.
Observer Pattern
은 디자인 패턴 중의 하나로, 어떤 객체 A가 있고, 그 객체의 상태 변화를 주시하는 옵저버들이 있다고 치자. 이때, A의 상태가 변하면 A는 자신을 주시하는 옵저버들에게 자신의 상태가 변했음을 알린다.
여기서 어떤 객체 A를 우리는 subject
라고 부르기로 했다. subject
를 주시하는 객체는 observer
라고 부른다.
한 개의 subject
에 여러 개의 observer
가 있을 수 있으므로, 1:N의 의존성을 가진다.
subject
는 자신을 주시하는 observer
들을 모아서 관리하고, 상태가 변하면 observer
들에게 일제히 알린다. observer
는 자신이 주시하는 subject
로부터 호출이 들어오면, 자기 자신이 할 일(callback)을 한다. 이러한 이유로 observer pattern
은 다음과 같은 장점을 가진다.
subject
와 observer
가 수행하는 일이 분리되어 캡슐화, 확장성, 유지보수 등에 유리하다.Interface
를 이용한 방법subject
는 ISubject
라는 인터페이스를, observer
는 IObserver
라는 인터페이스를 각각 상속받아서 구현한다.
public interface ISubject
{
void AddObserver(IObserver observer);
void RemoveObserver(IObserver observer);
void Notify();
void Notify(object obj);
}
public interface IObserver
{
public void OnNotify();
public void OnNotify(object obj);
}
subject
객체들은 ISubject
인터페이스를 상속받아서 AddObserver()
를 이용하여 자신을 주시하는 observer
들을 등록한다. 마찬가지로 RemoveObserver()
를 이용하여 자신을 주시하고 있는 observer
를 해지할 수 있다. Notify()
를 이용해서 등록된 observer
들에게 자신의 상태가 변했음을 알린다. (등록된 IObserver
객체들의 OnNotify()
를 호출한다.)
observer
객체들은 IObserver
인터페이스를 상속받아서 OnNotify()
를 이용해 주시 중인 subject
의 상태가 변했을 때의 로직을 수행한다.
delegate
를 이용한 방법 C#
에서는 delegate
를 이용해서도 Observer Pattern
을 구현할 수 있다고 한다. 그 이유는 delegate
의 다음과 같은 특성들 때문인데,
delegate
에는 반환값, 매개변수의 자료형이 같은 메서드들이 여러 개 등록 가능하다.
Invoke()
를 이용하여 자신에게 등록된 메서드들을 한 번에 호출한다.
public delegate void StatusChangeHandler(float current, float max);
public event StatusChangeHandler OnHPChanged;
public event StatusChangeHandler OnMpChanged;
public event StatusChangeHandler OnExpChanged;
void Start()
{
OnHPChanged += OnDead;
OnHPChanged += GameObject.Find("Player Info UI").transform.GetChild(0).GetComponent<InfoUI>().SetUIBar;
OnMpChanged += GameObject.Find("Player Info UI").transform.GetChild(1).GetComponent<InfoUI>().SetUIBar;
OnExpChanged += GameObject.Find("Player Info UI").transform.GetChild(2).GetComponent<InfoUI>().SetUIBar;
OnExpChanged += LevelUp;
currentHP = MaxHP;
currentMP = MaxMP;
currentExp = 0;
LV = 1;
}
현재 스탯과 최대 스탯을 매개변수로 받는 delegate
를 만들어서, 각각 HP가 변했을 때, MP가 변했을 때, 경험치가 변했을 때 호출될 메서드들을 등록했다.
public float MaxHP;
public float currentHP;
public float HP
{
get { return currentHP; }
set
{
currentHP = value;
OnHPChanged?.Invoke(currentHP, MaxHP);
}
}
스탯들은 property의 setter를 이용해서 delegate
를 호출한다.
Interface
, delegate
와 친해지기 위해서 Unity에서 간단한 Observer Pattern
실습을 해보기로 했다. 우선은 delegate
를 이용해 UI와 Player의 status를 연결시켜봤다.
아직 기능이 많이 없다. interface를 이용한 observer로 업적 시스템도 만들어볼 생각이다.
delegate는 아직 쓰면 쓸 수록 신기하다. 뭔가 멋있기도 하다. 친해지고 싶다. 근데 어렵다.