etc.

[Design Pattern] 옵저버 패턴(Observer Pattern)

mooni_ 2025. 4. 6. 20:22

옵저버 패턴(Observer Pattern) : 주체가 객체의 상태 변화가 있을 때마다 메서드 등을 통해 옵저버 목록에 있는 옵저버들에게 변화를 알려주는 패턴

> 주체 : 객체의 상태 변화를 보고 있는 관찰자

> 옵저버 : 객체의 상태 변화에 따라 전달되는 메서드 등을 기반으로 '추가 변화 사항'이 생기는 객체들을 의미

  • MVC(Model-View-Controller) 패턴에 사용됨
  • model(주체)에서 변경사항이 생겨 update() 메서드를 view(옵저버)에 알려주고 이를 기반으로 controller 작동

 


EX) Java에서의 Observer

1. Subject interface

interface Subject {
    void register(Observer obj);
    void unregister(Observer obj);
    void notifyObservers();
    Object getUpdate(Observer obj);
}

=> 옵저버 등록/제거 및 전체에게 알림을 보내는 등의 규칙 정의

 

2. Observer interface

interface Observer {
    void update();
}

=> Subject가 메세지를 보낼 때 호출하는 메서드

 

3. Topic class

class Topic implements Subject {
    private List<Observer> observers;
    private String message;
    
    public Topic() {
        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);
    }
    
    @Override
    public Object getUpdate(Observer obj) {
        return this.message;
    }
    
    public void postMessage(String msg) {
        System.out.println("Message sended to Topic: " + msg);
        this.message = msg;
        notifyObservers();
    }
}

=> 실제 Subject 구현

=> postMessage()로 새로운 메세지를 게시하면 내부 message를 업데이트하고 등록된 옵저버에게 notifyObservers()를 통해 알림

 

4. TopicSubscriber class

class TopicSubscriber implements Observer {
    private String name;
    private Subject topic;
    
    public TopicSubscriber(String name, Subject topic) {
        this.name = name;
        this.topic = topic;
    }
    
    @Override
    public void update() {
        String msg = (String) topic.getUpdate(this);
        System.out.println(name + ":: got message >> " + msg);
    }
}

=> 실제 Observer 구현

=> update()가 호출되면 topic.getUpdate()를 통해 메세지를 가져옴

 

5. main()

public class HelloWorld {
    public static void main(String[] args) {
        Topic topic = new Topic();
        Observer a = new TopicSubscriber("a", topic);
        Observer b = new TopicSubscriber("b", topic);
        Observer c = new TopicSubscriber("c", topic);
        topic.register(a);
        topic.register(b);
        topic.register(c);
        
        topic.postMessage("amumu is op champion!!");
    }
}

=> Observer 3개 등록 -> 메세지 게시 후 등록된 옵저버에게 알림 -> 각 옵저버가 메세지 출력

 

 


EX) JavaScript에서의 Observer : 프록시 객체를 통해 구현 가능

const handler = {
  get: function(target, name) {
    return name === 'name' ? `${target.a} ${target.b}` : target[name];
  }
};

const p = new Proxy({ a: 'MOONI', b: 'KIM' }, handler);

console.log(p.name); // MOONI KIM

> 프록시 객체 : 어떠한 대상의 기본적인 동작의 작업을 가로챌 수 있는 객체

> JS에서 프록시 객체의 매개변수 : target(프록시할 대상), handler(target 동작을 가로채고 동작의 내용을 담은 함수)

  • get() 트랩을 정의함으로써, 속성 접근 시 커스텀 로직을 실행할 수 있습니다.
  • p.name을 호출하면 handler.get()이 실행되어, ab 속성 값을 조합해서 반환하게 됩니다.