EveryDay.DevUp

[Unity] 프레임워크 개발 - 3. 기본 구조 ( 옵저버 패턴 ) 본문

FrameWork

[Unity] 프레임워크 개발 - 3. 기본 구조 ( 옵저버 패턴 )

EveryDay.DevUp 2020. 4. 30. 15:17

옵저버 패턴 : 변화가 있는 대상과 대상을 관찰하는 관찰자로 이루어지는 구조

● 옵저버 패턴의 구현

▶ 사용 예시 : Screen의 크기가 실시간으로 변화 되는지 감지하다가, Screen의 변화가 생기면 하위의 UI 크기를 변경할 때 사용

▶ 범용적으로 사용하기 위해 인터페이스로 구현

IObserver : 대상을 관찰하는 관찰자로 대상의 변화 시점에 OnNotify를 통해 감지

public enum OBSERVER_STATE
{
    PROGRSS, // 현재 관찰 중인 상태
    REMOVE, // 관찰이 끝났기 때문에 삭제 요청을 한 상태
}

public interface IObserver 
{
    int Priority { get; set; } // 처리 우선순위
    OBSERVER_STATE State { get; set; } // 현재 상태 값
    void OnResponse(object obj); // 변화된 상태값을 받는 함수
}

ISubject : 관찰자의 대상으로, 관찰자들의 추가, 삭제 및 상태 변화 시의 OnNotify를 호출

public interface ISubject 
{
    void AddObserver( IObserver observer ); // 관찰자 추가
    void RemoveObserver( IObserver observer ); // 관찰자 삭제
    void OnNotify(); // 상태 변화 시 관찰자에게 알림
}

대상의 기본적인 로직은 큰 변화가 없을 것으로 생각되기 때문에 상속을 받아 사용할 수 있도록 Class를 구현

using System.Collections.Generic;
using UnityEngine;

public class Subject : MonoBehaviour, ISubject
{
	List<IObserver> observers;

	public void AddObserver(IObserver observer)
	{
		if( observers == null )
		{
			observers = new List<IObserver>();
		}

		observer.State = OBSERVER_STATE.PROGRSS;
		observers.Add( observer );
		observers.Sort( ComparePriority );
	}

	int ComparePriority(IObserver a, IObserver b)
	{
		return a.Priority.CompareTo( b.Priority );
	}

	public void RemoveObserver(IObserver observer)
	{
		observer.State = OBSERVER_STATE.REMOVE;
	}

	public void OnNotify()
	{
		if( observers != null )
		{
			IObserver obserber;
			for( int i = 0, icount = observers.Count; i < icount; i++ )
			{
				obserber = observers[i];
				if( obserber != null && obserber.State == OBSERVER_STATE.PROGRSS )
				{
					obserber.OnResponse( this );
				}
			}

			for( int i = observers.Count - 1; i >= 0; i-- )
			{
				obserber = observers[i];
				if( obserber != null )
				{
					if( obserber.State == OBSERVER_STATE.REMOVE )
					{
						observers.RemoveAt( i );
					}
				}
			}
		}
	}
}

▶ 관찰하는 대상이 사라지는 경우에는 OnNotify가 호출되지 않는다는 이슈 외에는 코드에 영향을 줄만한 요소가 없음

▶ 관찰자가 사라지는 경우, 대상이 사라진 관찰자를 알 수 없다면 OnNotify중 에러가 날 가능성이 높음

▶ OnNotify중 관찰자가 사라질 수도 있는 경우가 있기 때문에 호출 후 삭제 요청 상태인 관찰자를 삭제 처리함