반응형

정의


 

정말 많이 쓰이는 디자인 패턴 중 하나인 옵저버 패턴은 아래와 같은 정의를 가지고 있다.

 

한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에게 연락이 가고 자동으로 내용이 갱신되는 방식으로, 일대다(one-to-many) 의존성을 정의한다.

 

아래의 그림과 같이, 한 Subject가 자신의 상태가 바뀌었음을 다수의 Observer 들에게 통지(Notify)하는 방식을 가지고 있는 패턴이다. 옵저버 패턴은 RxJava, Swing 라이브러리 등 많은 곳에서 활용하고 있는 디자인 패턴이다.

 

 

 

 

 

문제 상황


 

한 신문사가 있고, 이 신문사에서 출간되는 신문을 구독하는 다수의 구독자가 있는 상황을 고려해 보자.

구독자들은 신문이 배달될 때마다 바로 신문을 읽고 싶은 상황이다.

이를 위의 그림과 같이 정리하면 아래와 같이 나타낼 수 있다.

 

 

옵저버 패턴을 정의한 그림과 상당히 유사한 것을 볼 수 있다. 그렇다면 옵저버 패턴은 어떤 식으로 구현할 수 있을까?

옵저버 패턴에서는 우선 Subject, Observer 라고 불리는 두 개의 인터페이스가 주축이 된다.

 

  • Subject 에서는 발행하고자 하는 관심사를 등록된 Observer 들에게 전달하는 역할을 하고,
  • Observer 에서는 받고자 하는 관심사를 발행하는 Subject에게 등록하여 발행된 관심사를 전달받는 역할을 한다.

 

그리고 이 2개의 인터페이스를 구현해 옵저버 패턴을 이루게 된다.

이를 클래스 다이어그램으로 표현하면 아래와 같다.

 

 

Subject 의 경우, 구체적으로 위와 같이 3개의 메소드를 가진다.

  • 구독을 원하는 Observer를 등록하는 기능을 위해, registerObserver(Observer) 메소드를 가진다.
  • 구독 해제를 원하는 Observer를 위해, removeObserver(Observer) 메소드를 가진다.
  • 관심사 발행을 위한 notifyObservers() 메소드를 가진다.

 

Observer 의 경우, 아래와 같이 1개의 메소드를 가진다.

  • Subject로부터 발행된 관심사를 통한 구체적인 행동을 기술할 update() 메소드를 가진다.

 

참고로, 위의 다이어그램에서 볼 수 있듯이 Subject와 Observer는 서로에게 통지, 구독에 대한 기능을 수행해줄 뿐 상대방이 가진 구체적인 역할을 알 수는 없다.

이와 같이 최대한 서로의 정보를 모르는 채로 제한적인 기능만을 수행하도록 하는 것을 느슨한 결합 (Loose-Coupling) 이라고 한다.

 

이와 같은 인터페이스를 직접 구현한 NewspaperCompany, Subscriber 객체를 통해 관심사의 발행을 처리할 코드를 작성할 수 있다.

아래의 코드 예시를 통해 이해할 수 있을 것이다.

 

 

 

 

구현


public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObservers();
}
public interface Observer {
    public void update(String title);
}
import java.util.ArrayList;
import java.util.List;
 
public class NewspaperCompany implements Subject {
    private List<Observer> observers;
    String title;
 
    public NewspaperCompany() {
        observers = new ArrayList<Observer>();
    }
 
    public void registerObserver(Observer o) {
        observers.add(o);
    }
 
    public void removeObserver(Observer o) {
        observers.remove(o);
    }
 
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(title);
        }
    }
 
    public void publish(String title) {
        this.title = title;
        notifyObservers();
    }
}
public class Subscriber implements Observer {
    String name;
 
    public Subscriber(String name) {
        this.name = name;
    }
 
    public void update(String title) {
        System.out.println(this.name + ": I got newspaper!");
        System.out.println("  - Title: " + title);
    }
}
public class NewspaperTest {
    public static void main(String[] args) {
        NewspaperCompany newspaperCompany = new NewspaperCompany();
        Subscriber steve = new Subscriber("Steve");
        Subscriber peter = new Subscriber("Peter");
        Subscriber jane = new Subscriber("Jane");
 
        newspaperCompany.registerObserver(steve);
        newspaperCompany.registerObserver(peter);
        newspaperCompany.registerObserver(jane);
 
        newspaperCompany.publish("Oil price arise shortly!");
        newspaperCompany.publish("Lily will get marry at April!");
    }
}

 

 

 

 

참고


 

헤드 퍼스트 디자인 패턴, 한빛 미디어

반응형
복사했습니다!