옵저버 패턴 (Observer Pattern)
객체의 상태 변화을 감지하고 연결된 다른 객체의 상태를 쉽게 변경할 수 있도록 한다.
일대다 의존 관계를 구성해서 하나의 객체가 상태를 변경하면 모든 의존 객체에게 자동으로 알림이 전송되고 업데이트 하는 패턴이다.
주로 사용하는 곳
알림, 이벤트 기능이 필요한 대부분의 기능에서 해당 패턴을 사용한다.
- Android의 Event Listener
- 브라우저의 Event Handler
- Java Swing 라이브러리(GUI)
이외에도 GUI 프로그래밍을 하거나 메시지 발송과 같은 기능을 사용한다면 옵저버 패턴이 빠질 수 없다.
용어 정리
- Subject : 상태 변경을 알려주는 객체 (발행인)
- Observer : 상태 변경에 대한 알림을 받는 객체 (구독자)
헷갈리는 개념 정리
Publish - Subscribe 패턴(Pub-Sub Pattern)과 관련이 있는가? Observer 패턴의 또 다른 이름?
같은 패턴이 아니다.
관련은 있지만 Publish-Subscribe 패턴은 '토픽' 이라는 것을 통해 구독자가 다양한 유형의 메시지에 관심을 표현할 수 있도록 하고,
Message Broker(이벤트 버스)를 두어 발행인과 구독자 사이를 더욱 확실히 분리할 수 있는 더욱 복잡한 패턴이다.
주로 미들웨어 시스템에서 많이 사용된다.
Observer 패턴은 Observer와 Subject가 서로를 인지하지만 Pub-Sub 패턴의 경우 서로를 전혀 몰라도 상관없다.
그래서 Observer 패턴의 경우 Subject에 Observer를 등록하고 Subject가 직접 Observer에 직접 알려주어야 한다.
Pub-Sub 패턴의 경우 Publisher가 Subscriber의 위치나 존재를 알 필요없이 Message Queue와 같은 Broker 역할을 하는 이벤트 버스에 메시지를 던져 놓기만 하면 된다. 마찬가지로 Subscriber 역시 Publisher의 위치나 존재를 알 필요없이 Broker의 상황을 모니터링하다가 원하는 토픽의 메시지를 받고 작업하면 된다.
따라서 Observer 패턴에 비해 Pub-Sub 패턴이 더 낮은 결합도를 보인다.
Publisher와 Subscriber가 서로의 존재를 알 필요가 없기 때문에 당연히 소스코드 역시 겹치거나 의존할 일이 없다.
만약 결합도가 높다면 의도했거나, 잘못된 코드일 가능성이크다.
그리고 Observer 패턴은 대부분 동기(synchronous) 방식으로 동작하는 반면,
Pub-Sub 패턴은 대부분 비동기(asynchronous) 방식으로 동작한다. Pub-Sub 패턴은 Broker로 Message Queue를 많이 사용하기 때문이다.
낮은 결합도의 힘
Pub-Sub에 비해 높은 결합도를 가진 Observer 패턴이지만 이는 상대적일 뿐 Observer 패턴도 낮은 결합도를 지향하는 디자인 패턴이다.
낮은 결합도의 장점
- Subject가 Observer에 대해 알고 있는 유일한 것은 Observer가 특정 인터페이스를 구현한다는 것 뿐이다.
Observer의 구체적인 클래스, Observer가 수행하는 작업 또는 그에 대한 다른 정보를 알 필요가 없다. - 언제든지 새로운 Observer를 추가할 수 있다.
주체가 의존하는 유일한 것은 Observer 인터페이스를 구현하는 객체 리스트이므로 원할 때마다 새로운 Observer를 추가할 수 있다.
런타임에 Observer를 추가할 수 있고 언제든지 제거할 수도 있다. - 새로운 유형의 Observer를 추가하기 위해서 Subject를 수정할 필요가 없다.
주제는 상관없이 Observer 인터페이스를 구현하는 모든 객체에 알림을 전달한다. - Subject나 Observer를 서로 독립적으로 재사용할 수 있다.
- Subject나 Observer의 변경 사항은 다른 클래스에 영향을 끼치지 않는다.
옵저버 패턴을 적용한 기상 관측 애플리케이션 다이어그램
- Subject의 구현체인 WeatherData는 observerList를 가지고 있다.
- Observer의 구현체인 ThirdPartyDisplay, CurrentConditionsDisplay, StatisticsDisplay, ForecastDisplay는 자신의 상태를 update하는 메서드를 가지고 있다.
- Subject의 값이 변경되면 Subject를 구독하는 observer들에게 알림(notifyObservers)을 전송한다.
Subject의 구현체인 WeatherData 객체
public class WeatherData implements Subject {
private static List<Observer> observerList = new ArrayList<>();
private float temperature;
private float humidity;
private float pressure;
@Override
public void registerObserver(Observer o) {
observerList.add(o);
}
@Override
public void removeObserver(Observer o) {
observerList.remove(o);
}
@Override
public void notifyObservers() {
observerList.forEach(o -> o.update(temperature, humidity, pressure));
}
public void getMeasurements() {
}
public void setMeasurements(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
this.pressure = pressure;
}
}
- Observer 추가, 삭제, 알림 기능을 메서드로 가지고 있다.
구현이 어렵지 않고 이해하기도 쉬운 패턴이라고 생각된다.
하지만 낮은 결합도를 지향하는 패턴인 만큼 Kafka의 Pub-Sub 구조라던지, 모바일에서 다양한 Listener 기본 패턴으로 활용되는 모습을 보인다.
Java는 Observable 클래스(Subject)와 Observer 인터페이스를 제공했다.
하지만 Java9 이후로 이들은 Deprecated 되었는데 대부분의 사람들이 자체적으로 Observer Pattern 을 구현하는 것이 더 쉽다고 느꼈기 때문에 Observer/Observable 클래스를 사용하지 않게 되었다.
'Lang > Java' 카테고리의 다른 글
[Java] 가비지 컬렉션(GC, Garbage Collection) 기초 (4) | 2022.11.12 |
---|---|
전략 패턴 (Strategy Pattern) (3) | 2022.10.04 |
[Java] Lambda 특징과 활용 (1) | 2022.10.03 |
함수형 프로그래밍과 Java #1 (6) | 2022.09.08 |
[디자인 패턴] 싱글톤 패턴 (Creational) (0) | 2022.01.10 |