본문 바로가기

Computer Science/Design Pattern

[디자인 패턴] 옵저버(Observer) 패턴

정의

옵저버 패턴은 주체가 어떤 객체의 상태 변화를 관찰하다가 상태 변화가 있을 때 마다 메서드 등을 통해 옵저버 목록에 있는 옵저버에게 변화를 알려주는 패턴이다.

  • 객체와 주체가 분리되어 있을 수도 있고, 객체와 주체가 합쳐진 옵저버 패턴이 있을 수도 있다.
    여기서 주체란, 객체의 상태 변화를 보고있는 관찰자이며, 옵저버들이란 이 객체의 상태 변화에 전달되는 메서드등을 기반으로 추가적인 변화 사항들이 생기는 객체들을 의미한다.
  • 옵저버 패턴은 주로 이벤트 기반 시스템에 사용하며, MVC 패턴에도 많이 사용된다. 예를 들어, 모델에서 변경사항이 생겨 update() 메서드로 옵저버인 뷰에 알려주고 이를 기반으로 컨트롤러 등이 작동하는 방식이다.

옵저버 패턴의 장점

  • 주체와 관찰자들 사이의 결합도를 낮출 수 있다. 주체와 관찰자들은 서로 독립적으로 존재할 수 있으며, 주체의 변경이 있어도 관찰자들은 그에 대해서 더이상 알 필요가 없다.
  • 주체와 관찰자들 사이의 일관성을 유지할 수 있다.
  • 새로운 관찰자를 추가하기가 쉽다.

옵저버 패턴의 단점

  • 많은 관찰자들이 존재할 경우, 주체에서 관찰자들을 일괄적으로 알릴 때 성능 이슈가 발생할 수도 있다.
  • 관찰자들이 동일한 이벤트를 처리해야 할 경우, 관찰자들의 처리 순서가 중요한 경우도 있을 수 있다.

옵저버 패턴 예시 자바코드

해당 자바코드를 통해 옵저버 패턴이 어떻게 쓰이는지 알아보자.

먼저, 주체와 관찰자의 인터페이스를 정의해준다.

// Subject(주체) 인터페이스
public interface Subject {
	void registerObserver(Observer o); // 관찰자 등록
    void removeObserver(Observer o); // 관찰자 제거
    void notifyObservers(); // 관찰자들에게 알림
}
// Observer(관찰자) 인터페이스
public interface Observer {
	void update(int data); // 주체로부터 상태 변경 알림을 받음
}

구체적인 주체 클래스를 정의한다. 여기서, 데이터를 변경하면 해당 주체에 속한 옵저버들에게 상태가 변했다는 것을 notifyObservers() 메서드를 통해서 알려준다. 

// 구체적인 주체 클래스
class Topic implements Subject {
	private List<Observer> observers;
    private int data;
    
    public ConcreteSubject(){
    	observers = new ArrayList<>();
    }
    
    public void registerObserver(Observer o) {
    	observers.add(o);
    }
    
    public void removeObserver(Observer o){
    	observers.remove(o);
    }
    
    public void notifyObservers(){
    	this.observers.forEach(Observer::update);
    }
    
    public void setData(int data){
    	this.data = data;
        notifyObservers(); // 상태 변경 후 관찰자들에게 알림
    }
}

구체적인 관찰자 클래스를 정의한다.
주체에서 데이터를 변경해서 각 옵저버들에게 상태를 변화시키면 update 메서드가 호출된다.

// 구체적인 관찰자 클래스
class TopicSubscriber implements Observer {
	private int data;
    
    public void update(int data) {
    	this.data = data;
        System.out.println("관찰자가 업데이트 되었습니다. " + data);
    }
}
// 사용 예시
public class Main {
	public static void main(String args[]){
    	Topic subject = new Topic();
        TopicSubscriber observer1 = new TopicSubscriber();
        TopicSubscriber observer2 = new TopicSubscriber();
        
        subject.registerObserver(observer1);
        subject.registerObserver(observer2);
        
        subject.setData(1); // Observer update 1
        
        subject.removeObserver(observer1);
        
        subject.setData(2); // Observer update 2
    }
}