본문 바로가기

디자인 패턴

6. 옵저버 패턴 (Observer Pattern)

객체의 상태 변화를 관찰하는 관찰자들, 즉 옵저버들의 목록을 객체에 등록하여 상태 변화가 있을 때마다 
메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴이다.
- 위키백과 -

이번에 알아볼건 옵저버 패턴이다.

 

쉽게 말하면 유튜브 구독과 유사하다고 볼 수 있다.

유튜버관찰할 객체가 되고, 이를 구독한 시청자관찰자가 되는것이다.

새로운 영상이나 커뮤니티 글을 올리게 되면 구독자들에게 알림이 가는 것이 옵저버 패턴이다.

(실제로는 알람 설정까지 해야 하지만)

 

아래 코드를 통해 형태를 알아보자.

 

public delegate void VideoHandler(string url);

public class Youtuber
{
    public event VideoHandler Subscriber;

    public void OnVideoUpdate(string url) =>
        Subscriber?.Invoke(url);
}

public class YoutubeViewer
{
    private string name;

    public YoutubeViewer(string name) => this.name = name;

    public void Subscribe(Youtuber youtuber) =>
        youtuber.Subscriber += OnNewVideo;

    public void UnSubscribe(Youtuber youtuber) =>
        youtuber.Subscriber -= OnNewVideo;

    void OnNewVideo(string url) =>
        Console.WriteLine($"{name} 에게 {url} 알림");
}

 

VideoHandlerdelegate 로, 새로운 영상의 주소를 보내주기 위한 이벤트 핸들러로 사용된다.

C# 에서는 Action 등의 이미 정의된 delegate 가 있기 때문에 편리하게 구현이 가능하며

앞선 커맨드 패턴 (Command Pattern) 이나 함수 포인터 등의 비슷한 기능들로 구현해도 된다.

 

여기서 위와 같이 직접적으로 데이터를 넘겨주는 방식을 푸시(push),

알림만 전달하고 관찰자가 직접 데이터를 가져오는 방식을 풀(pull) 이라고 한다.

 

Youtuber 객체에는 VideoHandler 로 이벤트 변수를 만들어서 알림을 보낼 구독자 목록을 만들었다.

 

C# 에서 delegate 는 +=, -= 로 메소드를 추가, 삭제가 가능하며

event 로 지정 시 해당 추가, 삭제 기능만 외부에서 접근이 가능하다.

 

YoutubeViewer 객체에서는 Youtuber 객체를 받아서 구독 또는 구독 취소를 할 수 있으며

이벤트 핸들러로 추가할 OnNewVideo 메소드가 있다.

 

이를 사용해보면 다음 코드와 같다.

 

var youtuber = new Youtuber();

var sub1 = new YoutubeViewer("김철수");
sub1.Subscribe(youtuber);
var sub2 = new YoutubeViewer("아케");
sub2.Subscribe(youtuber);

youtuber.OnVideoUpdate("새로운 영상 1");
sub2.UnSubscribe(youtuber);
youtuber.OnVideoUpdate("새로운 영상 2");

 

"새로운 영상 1" 은 김철수와 아케 모두에게 알림이 가지만

"새로운 영상 2" 는 아케는 구독을 취소했기 때문에 김철수에게만 알림이 가게 된다.


내용을 정리해보며 마치도록 하겠다.

 

  • 목적 : 하나의 특정 객체다수의 메소드등록하여 상태 변화시 발생하는 이벤트분산시킨다.
  • 방법 : 관찰할 객체관찰자들의 이벤트 핸들러 메소드를 등록하여 사용한다.

옵저버 패턴은 UI 환경에서는 필히 사용되는 패턴이다.

MVC 패턴 (Model-View-Controller Pattern) 이라고 하며 모델(데이터)뷰(UI) 를 연결하는 데 사용된다.

이를 적용하면 데이터가 변경되었을 때 알림만 주면 자동으로 연결된 뷰들이

데이터에 맞춰 화면을 갱신하게 될 것이다.

 

또는 싱글턴 패턴 (Singleton pattern) 과 함께 사용하여 전체적인 데이터, 네트워크 패킷 등의 변화에 따라

한 곳에서 이벤트를 처리할 수 있는 시스템을 구현할 수도 있을 것이다.

 

 

 

추가로 이 글이 C# 으로 작성되었기 때문에 주의점을 말하자면

무명 메소드, 람다식을 delegate 에 등록하게 되면 동일한 내용이더라도 추후 삭제가 불가능하기 때문에

사용을 지양하거나 별도의 객체를 같이 등록하여 Key-Value 형태로 관리하여야 한다.

 

이는, 말 그대로 무명 메소드 이기 때문에 그 메소드를 찾을 수 없기 때문이다.

디버깅하여 추가된 메소드를 확인해보면 Void <Subscribe>b__2_0(System.String) 와 같은 게 추가된 걸 확인할 수 있다.