1 분 소요


Observer Pattern

옵저버 패턴이란 객체의 상태 변화를 관찰하는 옵저버들의 목록을 객체에 등록하여 객체의 상태 변화가 있을 때마다 객체에 등록된 옵저버들에게 알려주는 디자인 패턴이다.

쉽게 말해서 객체의 상태 변화가 생길 때, 이와 관련된 객체들에게 알림을 보내는 것이다.


옵저버 패턴의 장단점

장점

  • 실시간으로 한 객체의 변경사항을 다른 객체에 전파할 수 이다.
    • 옵저버 패턴을 사용하지 않으면 polling 방식으로 일정 시간마다 객체의 상태 변화를 체크해야 한다.
    • 이 방식을 사용하면 polling 시간 내에 이벤트가 발생했다가 사라지게 된다면 체크할 수 없다.
  • 느슨한 결합으로 시스템을 유연하게 하고 객체간의 의존성을 낮출 수 있다.

단점

  • 옵저버 패턴을 너무 많이 사용하게 되면 상태 관리가 어려워진다.


옵저버 패턴의 구조

옵저버 패턴의 핵심은 옵저버의 관찰 대상이 되는 객체에 옵저버들을 등록한 후, 객체에 이벤트가 발생했을 때 옵저버들에게 전파해서 각 옵저버들이 이벤트를 잘 처리할 수 있게 하는 것이다.

img1

  • 다이어그램을 보면 Subject (관찰 객체)는 옵저버들을 List로 가지고 있고 옵저버 등록, 삭제를 할 수 있다.
  • 그리고 이벤트가 발생했을 때, 옵저버들에게 전파할 수 있도록 notifyObservers() 메소드를 가지고 있다.
  • 각 옵저버들은 notify 함수를 구현함으로써 subject에 이벤트가 발생했을 때 처리할 동작을 정의한다.
  • 주의점 : 옵저버 패턴을 사용한 시스템에서는 반드시 재귀 호출을 막는 메커니즘이 요구된다.
    • 이벤트가 발생했을 때, 옵저버1과 옵저버2가 처리 동작 과정에서 서로를 변경한다면 무한 재귀 호출이 될 수 있다.


단순한 옵저버 패턴 구현

  • 사람(주인)애완동물의 관계로 옵저버 패턴을 구현해보자.
  • 동물에는 Dog, Cat이 있다고 하고 이벤트에 대해서 각 옵저버들의 동작을 정의해보자.
// subject interface
class Owner {
  	//Animal (observer) 를 리스트로 가지고 있음.
    private List<Animal> animals;

    public Owner() {
        this.animals = new ArrayList<>();
    }

  	//Animal 추가
    public void add(Animal animal) {
        if (!animals.contains(animal)) {
            animals.add(animal);
        }
    }
  
  	//Animal 제거
    public void delete(Animal animal) {
        animals.remove(animal);
    }
  
  	//event 발생 -> Animal(observer) 들에게 알림
    public void notifyAnimals() {
        this.animals.forEach(animal::notify);
    }
}

// observer interface
public interface Animal {
    public void notify()
}

// observer Dog
class Dog implements Animal {
    public void notify() {
        system.out.println("멍멍");
    }
}

// observer Cat
class Cat implements Animal {
    public void notify() {
        system.out.println("먀먀");
    }
}
  • 위의 예시는 굉장히 단순한 예시이다. 실제로 사용될 때는 훨씬 복잡하게 사용된다.


정리

  • 옵저버 패턴은 한 객체의 상태 변화에 대해 그 객체에 의존하는 다른 객체들에게 자동으로 연락을 보내서 정보를 갱신시키는 디자인 패턴이다.
  • 연결할 때, 인터페이스를 이용해서 느슨한 결합을 유지한다. subject, observer 인터페이스를 적용한다.