목차
옵저버 패턴
옵저버 패턴(Observer Pattern)은 객체 지향 프로그래밍에서 이벤트 구독 및 발행을 처리하는 데 사용되는 디자인 패턴입니다.
즉, 옵저버 패턴은 한 객체가 주체 역할을 하고 다른 객체가 관찰자 역할(리스너)로 일대 다 관계를 형성하는 것이 핵심입니다.
(이벤트 패턴과의 차이점은 옵저버 패턴은 주체자와 관찰자가 서로를 알고 있다는 것에 차이점이 있습니다.)
UML
옵저버 패턴의 UML은 위와 같습니다.
주체자(Subject)
•
registerObserver : 옵저버를 등록합니다.
•
removeObserver : 옵저버를 제거합니다.
•
notifyObservers : 옵저버에게 알림을 보냅니다.
옵저버 패턴의 장단점
장점
•
역동성: 주체에 필요한 만큼의 객체를 관찰자로 추가하고 런타임에 동적으로 제거할 수 있습니다.
•
일대다: 일대다 관계가 있는 객체 간 이벤트 처리 시스템 구현 문제를 해결할 수 있습니다.
단점
•
무질서: 관찰자가 알림받는 순서를 보장하지 않습니다. 둘 이상의 옵저버 객체가 속성을 공유하고 특정 순서에 맞춰 함께 동작해야 한다면, 기본 형태의 옵저버 패턴은 적절하지 않습니다.
(프로그래머가 기본 형태가 아닌 그 이상을 구현한다면 위 단점이 사라질 수 있지만, 옵저버 패턴을 세분화해야 할 수도 있고 그럴 경우 옵저버 패턴이 아닌 다른 패턴이 더 적절할 수 있습니다.)
•
누수: 서로 간의 참조는 메모리 누수를 일으킬 수 있습니다. 제대로 분리 및 삭제를 구현해야 합니다.
(예를 들어, 등록한 옵저버가 사라졌을 경우, 주체자의 옵저버 리스트에서도 사라지게 만들어야 합니다.)
옵저버 패턴 구현하기
•
주체(Subject) 인터페이스 생성: 이 인터페이스는 옵저버를 추가, 제거, 알림하는 메서드를 정의합니다.
public interface ISubject
{
void RegisterObserver(IObserver observer);
void RemoveObserver(IObserver observer);
void NotifyObservers();
}
C#
복사
•
옵저버(Observer) 인터페이스 생성: 이 인터페이스는 주체로부터 알림을 받는 메서드를 정의합니다.
public interface IObserver
{
void Update();
}
C#
복사
•
주체 클래스 구현: 주체 인터페이스를 구현하는 클래스를 작성합니다. 이 클래스는 옵저버 목록을 관리하고, 상태가 변경될 때마다 옵저버에게 알림을 전송합니다.
public class Subject : ISubject
{
private List<IObserver> observers = new List<IObserver>();
public void RegisterObserver(IObserver observer)
{
observers.Add(observer);
}
public void RemoveObserver(IObserver observer)
{
observers.Remove(observer);
}
public void NotifyObservers()
{
foreach (var observer in observers)
{
observer.Update();
}
}
// 주체의 상태 변경 메서드 예시
public void ChangeState()
{
// 상태 변경 로직...
// 상태가 변경되었음을 옵저버에게 알림
NotifyObservers();
}
}
C#
복사
•
옵저버 클래스 구현: 옵저버 인터페이스를 구현하는 클래스를 작성합니다. 이 클래스는 주체로부터 알림을 받아 업데이트되는 메서드를 포함합니다.
public class Observer : IObserver
{
public void Update()
{
// 주체로부터 알림을 받았을 때 수행할 작업
Debug.Log("Observer received an update from the subject");
}
}
C#
복사
•
사용 예시
void Start()
{
Subject subject = new Subject();
Observer observerA = new Observer();
Observer observerB = new Observer();
// 옵저버를 주체에 등록
subject.RegisterObserver(observerA);
subject.RegisterObserver(observerB);
// 주체의 상태 변경 및 옵저버 알림
subject.ChangeState();
// 옵저버 제거
subject.RemoveObserver(observerA);
// 주체의 상태 변경 및 남은 옵저버에게만 알림
subject.ChangeState();
}
C#
복사
옵저버 패턴에 대하여…
사실 옵저버 패턴을 이런 식으로 구현하는 것 보다, C#으 리플렉션 기능 혹은 사용자 정의 어트리뷰트 기능과 SendMessage 기능으로도 충분히 구현히 가능합니다.
예를 들어, 아래의 코드와 같이 사용자 정의 어트리뷰트로 쉽게 구현도 가능하죠.
[EventListener("OnMyEvent")]
private void HandleMyEvent()
{
Debug.Log("My event has been triggered.");
}
C#
복사
코드에 정답이 없습니다.
해당 코드에 대해 편의성과 유지 보수, 성능을 모두 고려해 프로그래머가 해당 코드를 선택했다면, 그 것이 정답입니다.