Observer

2022. 3. 23. 00:00CSharp/Design Pattern

반응형

관찰하는 개체에 발생하는 모든 이벤트에 대해 여러 개체에 알리는 구독 메커니즘을 정의할 수 있는 동작 디자인 패턴

객체의 상태 변화를 관찰하는 관찰자들의 목록을 객체에 등록하여 상태 변화가 있을 때마다 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴이다. 주로 분산 이벤트 핸들링 시스템을 구현하는 데 사용된다. 발행/구독 (publish/subscribe) 모델로 알려져 있기도 하다.

 

이 패턴의 핵심은 옵저버 또는 리스너(listener)라 불리는 하나 이상의 객체를 관찰 대상이 되는 객체에 등록시킨다.

그리고 각각의 옵저버들은 관찰 대상인 객체가 발생시키는 이벤트를 받아 처리한다.

 

https://dev.to/danlee0528/design-pattern-the-observer-pattern-3oha

 

문제점

twitter 의 follow 기능을 처리 한다고 가정하자.

client 가 내가 follow 한 사람의 최신 메세지를 보고 싶다면 일정 시간마다 request 를 요청해서 최신 내용이 있으면 받아오는 방법으로 할 수 있다. 하지만 이런 방식은 network 에 많은 부하를 주고 너무 비효율 적인 방식이다. 

 

해결책

publisher class 에 구독 메커니즘을 추가하여 개별 개체가 해당 게시자에서 오는 message (event stream) 를 구독 하거나 취소할 수 있도록 한다.

 

구독 메커니즘을 통해 개별 개체가 이벤트 알림을 구독할 수 있다.

https://refactoring.guru/design-patterns/observer

 

게시자는 개체에서 특정 알림 메서드를 호출하여 구독자에게 알립니다.

https://refactoring.guru/design-patterns/observer

 

class diagram

https://refactoring.guru/design-patterns/observer

 

 

Publisher 

: 다른 개체에 대한 관심 이벤트를 발행한다. 

 이러한 이벤트는 게시자가 상태를 변경하거나 일부 동작을 실행할 때 발생한다. 

 게시자에는 새 구독자가 구독 및 취소할 수있다.

 

Subscriber (interface)

: 알림 인터페이스를 선언. 대부분의 경우 단일 update방법으로 구성.

 

ConcreateSubscribers

: 게시자가 발행한 알림에 대한 응답으로 몇 가지 작업을 수행.  게시자가 구체적인 클래스에 연결되지 않도록 이러한 모든 클래스는 동일한 인터페이스를 구현해야 한다.

 

 

적용

  • 객체의 상태를 변경하기 위해 다른 객체를 변경해야 할때
  • 실제 객체 집합을 미리 알 수 없거나 동적으로 변경되는 경우
  • 앱의 일부 개체가 다른 개체를 관찰해야 하지만 제한된 시간 동안 또는 특정 경우에만 패턴을 사용

 

점심시간에 학교에서 스마트 폰을 통해 알람을 알려준다. 

학생은 학생 식당으로 가고 교사는 교원 식당으로 간다. 

이것을 코드로 구현해 보자

 

Publisher

public interface IPublisher
{
    void Subscribe(ISubscriber observer);
    void Unsubscribe(ISubscriber observer);
    void Notify();
}

public class LunchAlarm : IPublisher
{
    private List<ISubscriber> _observers = new List<ISubscriber>();
    public void Subscribe(ISubscriber observer)
    {
        Console.WriteLine($"{observer.GetType().Name} 은 이제부터 점심 알람을 받겠다.");
        this._observers.Add(observer);
    }
    public void Unsubscribe(ISubscriber observer)
    {
        this._observers.Remove(observer);
        Console.WriteLine($"{observer.GetType().Name} 은 이제부터 점심 알람을 받지 않겠다.");
    }
    public void Notify()
    {
        Console.WriteLine("!!! 점심 시간을 알리는 알람이 울린다. !!! ...");
        foreach (var observer in _observers)
        {
            observer.Update(this);
        }
    }
    public void LunchStarted()
    {
        Console.WriteLine("!! 점심 시간이 되었다.!!");
        this.Notify();
    }
}

 

Subscriber

public interface ISubscriber
{
    void Update(IPublisher subject);
}

public class Student : ISubscriber
{
    public void Update(IPublisher subject) => Console.WriteLine("학생들이 식당으로 달린다.");
}

public class Teacher : ISubscriber
{
    public void Update(IPublisher subject) => Console.WriteLine("교사들이 교원 전용 식당으로 간다.");
}

사용법

var lunchAlarm = new LunchAlarm();
var student = new Student();
lunchAlarm.Subscribe(student);
var teacher = new Teacher();
lunchAlarm.Subscribe(teacher);
lunchAlarm.LunchStarted();
lunchAlarm.Unsubscribe(teacher);
lunchAlarm.LunchStarted();
// output
Student 은 이제부터 점심 알람을 받겠다.
Teacher 은 이제부터 점심 알람을 받겠다.
!! 점심 시간이 되었다.!!
!!! 점심 시간을 알리는 알람이 울린다. !!! ...
학생들이 식당으로 달린다.
교사들이 교원 전용 식당으로 간다.
Teacher 은 이제부터 점심 알람을 받지 않겠다.
!! 점심 시간이 되었다.!!
!!! 점심 시간을 알리는 알람이 울린다. !!! ...
학생들이 식당으로 달린다.

 

 

관련영상

https://youtu.be/OJ1wA-w3ni8

 

 

 

 

반응형

'CSharp > Design Pattern' 카테고리의 다른 글

Visitor (방문자)  (0) 2022.03.25
Strategy (전략패턴)  (0) 2022.03.24
Mediator  (0) 2022.03.22
Command  (0) 2022.03.21
Template Method  (0) 2022.03.18