본문 바로가기
Delvelopment/DesignPattern

[Design Pattern] 옵저버 패턴, 감시자 패턴 (Observer Pattern)

by 제제킴 2022. 5. 16.
반응형

옵저버 패턴은 일련의 객체 사이에서 일대다 관계를 정의한다. 한 객체의 상태가 변경되면 그 객체에 의존하는 모든 객체에 연락이 간다.

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

느슨한 결합(Loose Coupling)은 객체들이 상호작용할 수는 있지만 ,서로를 잘 모르는 관계를 의미한다. 느슨한 결합을 활용하면 유연성이 좋아지고 옵저버 패턴은 느슨한 결합을 보여주는 예이다.

  • 주제(subject)는 옵저버(observer)가 특정 인터페이스를 구현한다는 사실만 안다.
  • 옵저버(observer)는 언제든지 새로 추가할 수 있다.
  • 새로운 형식의 옵저버(observer)를 추가할 때도 주제(subject)를 변경할 필요가 전혀 없다.
  • 주제(subject)와 옵저버(observer)는 서로 독립적으로 재사용할 수 있다.
  • 주제(subject)나 옵저버(observer)가 달라져도 서로에게 영향을 미치지는 않는다.

→ 느슨하게 결합하는 디자인을 사용하면 변경 사항이 생겨도 무난히 처리할 수 있는 유연한 객체지향 시스템을 구축할 수 있다. 객체 사이의 상호의존성을 최소화 할 수 있기 때문이다.

OCP(Open-Closed Principle) Class는 확장에는 열려 있어야 하지만 변경에는 닫혀 있어야 한다.

옵저버 패턴은 새로추가하면 주제에 코드를 추가하지 않으면서 확장이 가능하다.

  • 장점
    • 실시간으로 한 객체의 변경사항을 다른 객체에 전파가 가능하다.
    • 느슨한 결합으로 시스템이 유연하고 객체간의 의존성을 제거할 수 있다 (OCP)
  • 단점
    • 너무 많이 사용하게 되면, 상태 관리가 힘들수 있다.
    • 데이터 배분에 문제가 생기면 큰 문제로 이어질 수 있다.

옵저버 패턴은 Push 방식 뿐만아니라 Pull방식으로도 사용할 수 있다.

Java8까지 Observer 인터페이스 까지 제공되었다. (9부터 deprecated 되었음, Flow 인터페이스를 제공, pub/sub)

 


 

 

옵저버 패턴 예시

package pattern.observer;

public class CurrentConditionsDisplay implements Observer {

    private float temperature;
    private float humidity;
    private WeatherData weatherData;

    public CurrentConditionsDisplay(WeatherData weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

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

    public void display() {
        System.out.println("현재 상태 : 온도 " + temperature + "F, 습도 " + humidity + "%");
    }

}
package pattern.observer;

public interface Observer {
    void update(float temp, float humidity, float pressure);
}
package pattern.observer;

public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObserver();
}
package pattern.observer;

import java.util.ArrayList;
import java.util.List;

public class WeatherData implements Subject {

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

    public WeatherData() {
        this.observerList = new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer observer) {
        observerList.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observerList.remove(observer);
    }

    @Override
    public void notifyObserver() {
        for (Observer observer : observerList) {
            observer.update(temperature, humidity, pressure);
        }
    }

    public void measurementsChanged(){
        notifyObserver();
    }

    public void setMeasurements(float temperature, float humidity, float pressure){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }

}
package pattern.observer;

public class WeatherStation {
    public WeatherStation() {
        WeatherData weatherData = new WeatherData();

        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
        weatherData.setMeasurements(78, 90, 29.2f);

    }
}

 


Observer (or Publish/Subscribe) (recognizeable by behavioral methods which invokes a method on an instance of another abstract/interface type, depending on own state)

반응형

댓글