옵저버 패턴 정의
제공자 (subject), 구독자 (subscriber)로 구분하여 다룬다. 제공자는 자신의 상태가 변할 경우 자신을 구독한 구독자에게 알리는 역할을 수행한다. 1 대 다 의존성을 가지는 패턴이다.
필요한 상황
1. 제공자의 정보가 변할 때마다 모든 구독자에게 알림을 보내야 하는 경우
2. 구독자의 리소스를 아껴야 할 경우 (제공자에게 데이터를 계속 요청하기보다는 콜백형태로 제공자에게 수동적으로 받기 때문)
3. 구독자 Class와 제공자 Class 간 결합성을 낮추고 싶은 경우
Class 다이어그램
코드
1. ISubject와 IObserver interface 코드
public interface ISubject
{
void RegistUser(IObserver observer);
void RemoveUser(IObserver observer);
void Broadcast();
}
public interface IObserver
{
void update(object sender, EventArgs evetArgs);
}
2. BroacastSubject Class 코드
public class BroadcastSubject : ISubject
{
private event EventHandler broadcast = null;
public int nCurrentState { get; private set; }
public void Broadcast()
{
if (broadcast != null)
{
broadcast(this, null);
}
else
{
Console.WriteLine("no Observer..");
}
}
public void ChangeValue(int nInputData)
{
nCurrentState = nInputData;
Console.WriteLine("===========Change Value! Let's Broacast to my Observer!! =============");
this.Broadcast();
}
public void RegistUser(IObserver observer)
{
broadcast += observer.update;
}
public void RemoveUser(IObserver observer)
{
broadcast -= observer.update;
}
}
3. Client_User Class 코드
public class Client_User : IObserver
{
public string strClientUserName = "";
public Client_User(string strClientUserName, ISubject subject)
{
this.strClientUserName = strClientUserName;
subject.RegistUser(this);
}
public void update(object sender, EventArgs eventArgs)
{
var broadcaster = sender as BroadcastSubject;
Console.WriteLine($"=============================================================");
Console.WriteLine($"{this.strClientUserName} GetData : {broadcaster.nCurrentState}");
}
}
4. Main 코드
BroadcastSubject broadcastSubject = new BroadcastSubject();
broadcastSubject.ChangeValue(3);
Client_User cu1 = new Client_User("user1", broadcastSubject);
broadcastSubject.ChangeValue(3);
Client_User cu2 = new Client_User("user2", broadcastSubject);
broadcastSubject.ChangeValue(4);
broadcastSubject.RemoveUser(cu2);
broadcastSubject.ChangeValue(5);
코드 설명
1. ISubject, IOversber interface 코드이다. 각 역할별로 필수로 구현해야 하는 함수를 정의했다.
2. ISubject interface를 적용시킨 BroadcastSubject 코드이다. EventHandler는 C#에서 제공하는 예약어로 해당 EventHandler에 아래와 같이 규격을 맞춘 함수를 등록하면 EventHandler 내부의 invocationlist에 등록되어 해당 EventHandler만 호출하면 등록한 함수를 모두 호출한다. 규격과 이용방법은 아래와 같다.
class TestClass
{
public event EventHandler broadcast = null;
void broacastToObserver()
{
if (broadcast != null)
{
broacast(this, null);
}
}
}
class ObserverClass()
{
public void update(object sender, EventArgs eventArgs)
{
//do something..
}
}
TestClass testClass = new TestClass();
ObserverClass obClass = new ObserverClass();
testClass.broacast += obClass.update; //EventHandler에 함수 등록
testClass.broacastToObserver(); //EventHandler 호출!!!!!!!
3. Client_User Class 코드의 특징점은 Observer 입장으로 보자면 생성자에서 Broadcast subject 인스턴스를 참조로 받아와서 자신을 등록하고, 이후 update 함수를 콜백형태로 받는 구조이다.
설명 보충을 위한 그림 자료
필요에 따라 추가 설명
1. 옵저버 패턴은 정말 많이 쓰인다. WPF에서도 사용자가 정의한 Class에 대해서 ObservableCollection 등 쓰이는데 이는 모두 GUI 상에 나와있는 버튼으로부터 실시간으로 알림을 받기 위해서다. (사실 정확히 뭐가 Subject이고 Observer 인지는 모른다)
2. 콜백 형태와 매우 유사하다.
정리 및 결론
오늘은 옵저버 패턴을 공부했다. 제법 아는 척하기 좋은 패턴이고 이미 많이 상용화되어 있다. 우리가 직접 이 패턴을 구현해야 할 때는 별로 없을 것 같다. 하지만 이런 패턴으로 구현되어 있는 구조를 본다면 빨리 알아보고 활용할 수 있는 개발자가 되자!!
'Program > SW Design Patterns' 카테고리의 다른 글
CH5 데코레이터 패턴 (1) | 2023.03.05 |
---|---|
CH4 팩토리 패턴 (0) | 2023.03.04 |
CH2 싱글턴 패턴 (0) | 2023.03.02 |
CH1 전략 패턴 (0) | 2023.03.02 |
개요 (0) | 2023.03.01 |