정의
정말 많이 쓰이는 디자인 패턴 중 하나인 옵저버 패턴은 아래와 같은 정의를 가지고 있다.
한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에게 연락이 가고 자동으로 내용이 갱신되는 방식으로, 일대다(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!");
}
}
참고
헤드 퍼스트 디자인 패턴, 한빛 미디어
'Programming > Design Pattern' 카테고리의 다른 글
[디자인패턴] 데코레이터 패턴(Decorator Pattern)이란 무엇인가? (0) | 2023.03.08 |
---|---|
[디자인패턴] 전략 패턴(Strategy Pattern)이란 무엇인가? (0) | 2023.03.07 |