# 옵저버(Observer) 패턴

# 옵저버 패턴이란 무엇인가요?

주체가 어떤 객체의 상태 변화를 관찰하다가 상태 변화가 있을 때마다 메서드 등을 통해 옵저버 목록에 있는 옵저버들에게 변화를 알려주는 디자인 패턴입니다.
여기서 주체란 객체의 상태 변화를 보고 있는 관찰자이며, 객체 자신이 주체가 될수도 있습니다. 옵저버들이란 이 객체의 상태 변화에 따라 전달되는 메서드 등을 기반으로 '추가 변화 사항'이 생기는 객체들을 의미합니다.

  • UML
    옵저버

# 예시 코드

  • Subject : 주체의 인터페이스
interface Subject {
    public void register(Observer obj); 
    public void unregister(Observer obj);
    public void notifyObservers();
    public Object getUpdate(Observer obj);
}
  • Observer : 옵저버 인터페이스 (옵저버들이 이것을 상속받는다.)
interface Observer {
    public void update();
}
  • Alarm : 주체
class Alarm implements Subject {
    private List<Observer> observers;   // 옵저버들을 담을 리스트
    private String message;
    
    public Alarm() {
        this.observers = new ArrayList<>();
        this.message = '';
    }
    
    @Override
    public void register(Observer obj) {
        if(!observers.contains(obj)) observers.add(obj);
    }
    
    @Override
    public void unregister(Observer obj) {
        observers.remove(obj);
    }
    
    @Override
    public void notifyObservers() {
        this.observers.forEach(Observer::update);   // 옵저버들의 update메소드를 실행시킴
    };
    
    @Override
    public Object getUpdate(Observer obj) {
        return this.message;
    };
    
    public void postMessage(String msg) {
        System.out.println("Alarm : " + msg);
        this.message = msg;
        notifyObservers();
    }
}
  • Subscriber : 옵저버들
class Subscriber implements Observer {
    private String name;
    private Subject alarm;
    
    public Subscriber(String name, Subject alarm) {
        this.name = name;
        this.alarm = alarm;
    }
    
    @Override
    public void update() {
        String msg = (String)alarm.getUpdate(this);
        System.out.println(name + " got alarm : "+ msg);
    }
}
  • 사용
public class Main{
    public static void main(String[] args) {
        Alarm alarm = new Alarm();  //
        Observer a = new Subscriber("a", alarm);    //옵저버 생성
        Observer b = new Subscriber("b", alarm);
        alarm.register(a);  // 옵저버를 등록해준다
        alarm.register(b);
        
        alarm.postMessage("새로운 영상이 업데이트 되었습니다!");
    }
}

# 옵저버 패턴의 장점은 무엇인가요?

  • 느슨한 결합으로 객체 사이의 상호 의존성을 최소화 할 수 있습니다.
  • 옵저버를 언제든 새로 추가, 제거할 수 있습니다.
  • 실시간으로 한 객체의 변화를 다른 객체에 전파할 수 있습니다.

# 옵저버 패턴의 단점은 무엇인가요?

  • 너무 많이 사용하면 상태관리가 힘들 수 있습니다.

# 옵저버 패턴을 실제로 사용한 예는 무엇이 있나요?

  • 프레임워크 Vue.js 3.0에서 ref나 reactive로 정의하면 해당 값이 변경되었을 때 자동으로 DOM에 있는 값이 변경되는데, 이는 프록시 객체를 이용한 옵저버 패턴을 이용하여 구현한 것입니다.
  • 주로 이벤트 기반 시스템에 사용되며 mvc패턴에도 사용됩니다. (Model에 변경 사항이 생기면 update메소드로 View에 알려주고 이를 기반으로 Controller가 작동됩니다.)
  • JAVA 내장 옵저버 라이브러리인 Observer인터페이스와 Observable클래스가 존재합니다.

# 참고자료

출처: 주홍철.면접을 위한 CS 전공지식 노트.서울:길벗,2022.
출처: https://velog.io/@hanna2100/%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4-2.-%EC%98%B5%EC%A0%80%EB%B2%84-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%85%90%EA%B3%BC-%EC%98%88%EC%A0%9C-observer-pattern [hanna2100.log]
출처: https://coding-factory.tistory.com/710 [코딩팩토리]