Provider - 이벤트를 발생시키면서(제공하면서) Observer를 관리하는 개체
자신이 관리하고 있는 Observer에 대하여 Subscribe하는 방법을 갖고 있고 이벤트 발생 함수를 invoke 한다.
Observer - Provider가 발생시키는 이벤트를 구독한다.
Observer는 Provider에 Subscibe 함수로 구독을 실행하고 그 반환 Unsubscribe 클래스 개체를 소유한다.
Observer는 원할 때 Unbsubscribe 개체 인스턴스를 이용하여 구독을 취소한다.
C#
Provider는 IObserable<T> 인터페이스를 구현한다.
public interface IObservable<out T>
{
IDisposable Subscribe(IObserver<T> observer);
}
IDisposable를 반환하는 이유는 구독을 취소하기 위해 Dispose() 함수를 이용하는 개체를 반환하기 때문이다.
T 타입은 주로 Provider가 제공하는 이벤트 타입을 의믜한다.
Provider 예시
BaggageHandler : IObserable<BaggageInfo>
공항에서 출발하거나 도착한 수화물 정보(이벤트)를 제공한다.
수화물 정보(BaggageInfo)는 다음과 같다.
public class BaggageInfo
{
private int flightNo;
private string origin;
private int location;
internal BaggageInfo(int flight, string from, int carousel)
{
flightNo = flight;
origin = from;
location = carousel;
}
public int FlightNumber
{
get { return flightNo; }
}
public string From
{
get { return origin; }
}
public int Carousel
{
get { return location; }
}
}
Subscribe 함수를 통해 관찰자를 구독한다. 관찰자가 구독을 취소하는 방법을 반환한다.
public class BaggageHandler : IObservable<BaggageInfo>
{
private List<IObserver<BaggageInfo>> observers = new List<IObserver<BaggageInfo>>();
private List<BaggageInfo> flights = new List<BaggageInfo>();
public BaggageHandler() { }
public IDisposable Subscribe(IObserver<BaggageInfo> observer)
{
// Check whether observer is already registered. If not, add it
if (!observers.Contains(observer))
{
observers.Add(observer);
// Provide observer with existing data
foreach (var item in flights)
observer.OnNext(item);
}
return new Unsubscriber<BaggageInfo>(observers, observer);
}
Unscriber는 IDisposable의 구현체로 구독을 취소하는 방법을 제공한다.
internal class Unsubscriber<BaggageInfo> : IDisposable
{
private List<IObserver<BaggageInfo>> _observers;
private IObserver<BaggageInfo> _observer;
internal Unsubscriber(List<IObserver<BaggageInfo>> observers, IObserver<BaggageInfo> observer)
{
_observers = observers;
_observer = observer;
}
public void Dispose()
{
if (_observers.Contains(_observer))
{
_observers.Remove(_observer);
}
}
}
관찰자 예시
ArrivalsMonitor 도착 정보 모니터
IObserver<BaggageInfo>를 구현하여 이벤트 발생 후 이벤트 처리, 완료, 에러 처리를 구현한다.
public interface IObserver<in T>
{
void OnCompleted(); // 완료 처리
void OnError(Exception error); // 오류 처리
void OnNext(T value); // 이벤트 처리
}
ArrivalsMonitor
도착 정보를 관찰하는 관찰자 클래스
public class ArrivalsMonitor : IObserver<BaggageInfo>
{
private string name;
private List<string> flightInfos = new List<string>();
private IDisposable cancellation;
private string fmt = "{0,-20} {1,5} {2,3}";
public ArrivalsMonitor(string name)
{
if (string.IsNullOrEmpty(name))
throw new ArgumentNullException("the observer must be assigned a name");
this.name = name;
}
public virtual void Subscribe(IObservable<BaggageInfo> provider)
{
cancellation = provider.Subscribe(this);
}
public virtual void Unsubscribe()
{
cancellation?.Dispose();
flightInfos.Clear();
}
public virtual void OnCompleted()
{
// 완료 처리
flightInfos.Clear();
}
public virtual void OnError(Exception e)
{
// 오류 처리
}
public virtual void OnNext(BaggageInfo info)
{
// 이벤트 처리
}
}
전체 코드 참고
https://learn.microsoft.com/ko-kr/dotnet/standard/events/observer-design-pattern-best-practices