Shong Studio의 정보 창고

[디자인 패턴] Observer Pattern (옵저버 패턴) - 직관적인 설명 & 예시 본문

디자인 패턴

[디자인 패턴] Observer Pattern (옵저버 패턴) - 직관적인 설명 & 예시

Shong Studio 2024. 3. 23. 12:09
728x90
반응형

안녕하세요 Shong Studio입니다.

디자인 패턴 중 "구독 & 알림" 개념의 느낌을 갖고있는 "Observer Pattern"에 대해서 알아보도록 하겠습니다.

 

Observer Pattern 이란?

옵서버 패턴(observer pattern)은 객체의 상태 변화를 관찰하는 관찰자들, 즉 옵저버들의 목록을 객체에 등록하여 상태 변화가 있을 때마다 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴이다.
주로 분산 이벤트 핸들링 시스템을 구현하는 데 사용된다. 발행/구독 모델로 알려져 있기도 하다.

Observer Pattern을 사용해야하는 이유는?

Publisher가 되는 특정 객체가 갖고 있는 값의 변화에 따라 다른 객체(Observer)를 호출해서 처리해야하는  상황이 있습니다.

이 때 Publisher 안에 ChangeValue(int a, int b, int c) 와 같은 함수 내에서 호출해줘야하는 객체(Observer)의 함수를 호출해서 구현을 만들 수 있습니다.

하지만, 호출해줘야하는 객체가 추가될 때마다 Publisher내에서도 추가되는 객체에 대한 클래스를 정의및 선언하고 객체를 만들고, 호출하는 등 여러가지 작업들을 해줘야하고 코드가 복잡해질수록 오류를 유발하기 쉽습니다.

이런 상황에서 Observer Pattern을 사용해서 Publisher와 Observer(Subscriber)사이의 의존성(Dependency)를 줄여줘서 Loose coupling한 구현을 한다면 추후 해당 코드를 요구사항에 맞게 확장하는데 있어서 편리함을 가져올 수 있습니다.

  • subejct 가 가진 정보는 observer interface 를 구현한 것 뿐이다.
  • Observer interface 를 구현만 하면 되니 추가, 교체, 동적 변경이 가능하다 (SOLID 의 OCP 원칙)
  • observer 가 변경된다고 해서 subject(Publisher) 가 바뀔 필요가 없다.
  • 독립적인 재사용 → 다른 용도로 써도 된다.
  • 서로 interface 를 알기 때문에 나머지가 바뀌어도 문제 없다.

※ 디자인의 원칙
서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결합하는 디자인을 사용해야 한다.

 

Observer Pattern을 어떻게 사용하는지 알아보자.

WeatherData라는 클래스를 사용해서 온도, 습도, 기압 value값의 변화에 따라서 각종 Display Observer에게 notify하는 예제를 들어서 설명하도록 하겠습니다.

WeatherData 예제에 대한 Observer Pattern Class Diagram

Subject(Publisher), Observer Interface 구현

public interface Subject {
	void registerObserver(Observer o);
	void removeObserver(Observer o);
	void notifyObservers();
}
public interface Observer {
	void update(float temp, float humidity, float pressure);
}

 

WeatherData 구현 

Observer 인터페이스를 Type으로 observers의 List를 만들어서 구독자 관리가 되는 것이 포인트 입니다.

이로써 Observer 인터페이스를 상속받는 어떠한 클래스가 확장되더라도 WeatherData에서는 그 클래스의 존재를 알 필요가 없습니다. (Loose coupling)

public class WeatherData implements Subject {

  public WeatherData() {
    observers = new ArrayList<>();
  }

  private List<Observer> observers;
  private float temperature;
  private float humidity;
  private float pressure;

  @Override
  public void registerObserver(Observer o) {
    observers.add(o);
  }

  @Override
  public void removeObserver(Observer o) {
    int index = observers.indexOf(o);
    if (index >= 0) {
      observers.remove(o);
    }
  }

  /**
   * 상태를 모든 observer 들에게 알려주는 역할을 한다.
   */
  @Override
  public void notifyObservers() {
    observers.stream()
        .forEach(observer -> observer.update(temperature, humidity, pressure));
  }

  public void measurementsChanged() {
    notifyObservers();
  }

  /**
   * 데이터를 받는곳, 데이터를 받으면 상태를 변경하고 모든 observer 에게 알려준다
   * @param temp
   * @param humidity
   * @param pressure
   */
  public void setMeasurements(float temp, float humidity, float pressure) {
    this.temperature = temp;
    this.humidity = humidity;
    this.pressure = pressure;
    measurementsChanged();
  }

}

 

Display 구현

Display 클래스는 Observer를 상속받고 있고, 생성자 내부에서 Subject를 파라미터로 받아서 구독신청을 진행하는 것 만으로 weatherData값의 상태변화에 따른 Notification을 받을 수 있습니다.

public class CurrentConditionDisplay implements Observer, DisplayElement {

  private float temperature;
  private float humidity;
  private Subject weatherData;

  public CurrentConditionDisplay(Subject subject) {
    this.weatherData = subject;
    weatherData.registerObserver(this);
  }

  @Override
  public void update(float temp, float humidity, float pressure) {
    this.temperature = temp;
    this.humidity = humidity;
    display();
  }

  @Override
  public void display() {
    System.out.println("Current condition: " +
        temperature + "F degrees and " + humidity + "% humidity");
  }

}

 

 

이상입니다. 감사합니다.

 

Java에서는 Observer Pattern을 더 편리하게 해주기 위한 Observable클래스를 제공해주고 있습니다.

관심있으면 알아보셔도 좋을 것 같습니다. ( java9 부터 deprecated )

728x90
반응형