해당 포스팅은 한빛 미디어 헤드퍼스트 디자인 패턴(에릭 프리먼, 엘리자베스 롭슨 저)를 통해 공부한 내용을 정리한 블로그입니다.

아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
좋은 프로그래머는 자기 두뇌를 사용한다. 그러나 좋은 가이드라인은 모든 케이스를 고려해야만 하는 노력을 줄여준다.
(Francis Glassborow, 개발자)

Observer 패턴 이해하기


신문사 + 구독자 = Observer 패턴(publish-subscribe 패턴과 다름)

  • 구성요소
    • 신문사 => 주제(Subject)
    • 구독자 => 옵저버(Observer)
  • 주제에서는 중요한 데이터를 관리
  • 주제의 데이터가 바뀌면 옵저버에게 이벤트(데이터가 바뀌었다는 소식)를 전달.
  • 주제를 구독하고 있는 옵저버에게 소식이 전달되었기에 전달받은 내용을 옵저버는 갱신.(최신 데이터 유지)

작동원리

  • 주제는 옵저버들에게 데이터를 전달.
  • 어떤 객체가 주제의 데이터를 전달받고 싶어하면 주제를 구독하면 됨.(옵저버가 되는 형태)
  • 주제의 데이터를 그만 업데이트하고 싶으면, 주제의 구독을 해지.

Observer 패턴 

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

observer pattern class diagram

느슨한 결합


  • 한 객체가 다른 객체에 너무 의존적이면 단단한 결합이라 함.

느슨한 결합

  • 객체가 부서질 가능성이 낮음
  • 객체의 세세한 부분까지 알 필요가 없음
  • 상호작용할 수 있지만 잘 모르는 관계
  • 다른 객체와 상관없이 설계하면 변화에 더 잘 대응할 수 있는 디자인을 만들 수 있음 => 유연한 디자인

옵저버 패턴에 적용한 내용

  • 주제는 옵저버가 특정 인터페이스(Observer interface)를 구현한다는 사실만 알고 있음.
  • 옵저버는 언제든 추가/제거 가능
  • 새로운 형식의 옵저버를 추가해도 주제 변경이 필요가 없음.
  • 주제와 옵저버는 서로 독립적으로 재사용 가능.
  • 주제나 옵저버가 달라져도 서로에게 영향을 미치지 않음.
💡 상호작용하는 객체 사이에는 느슨한 결합을 사용해야함.

풀 방식으로 코드 바꾸기


  • 이전까지의 방식
    • 주제가 옵저버에게 데이터를 보내는 푸시(PUSH)
  • 현재 사용할 방식
    • 옵저버가 주제로부터 데이터를 당겨오는 풀(PULL)

코드


/* 
 * observer interface
 */
public interface Observer {
    public void update(float temp, float humidity, float pressure);
    public void update();
}

/* 
 * display interface
 */
public interface DisplayElement {
    public void display();
}

public class CurrentConditionsDisplay implements Observer, DisplayElement {

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

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

    // PUSH 방식
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;

        display();
    }

    // PULL 방식
    public void update() {
        this.temperature = weatherData.getTemperature();
        this.humidity = weatherData.getHumidity();

        display();
    }

    public void display() {
        System.out.println("CurrentConditions Display");
        System.out.println("temperature = " + temperature + " humidity = " + humidity);

    }
}

/* 
 * subject interface
 */
public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer observer);
    public void notifyObservers();
}

public class WeatherData implements Subject {

    // 인스턴스 변수 선언
    private List<Observer> observers;
    private float temperature;
    private float humidity;
    private float pressure;

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

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

    public void removeObserver(Observer o) {
        observers.remove(o);
    }

    public void notifyObservers() {
        // Push방식
        // Observer들에게 갱신 값 보내주기.
        for (Observer o : observers) {
            o.update(temperature, humidity, pressure);
        }

        // Pull
        // Observer에서 값 가져오기
        for (Observer o : observers) {
            o.update();
        }

    }

    public void measurementsChanged() {

        notifyObservers();
        /*
         * 현재 구조에서는 display들이 update 메소드를 요청하는데 하나로 묶을 수 있을 것 같음.
         * 최신 측정 값을 가져오는 시점을 판단하기 어려움
         * Observer 패턴 도입.
         */
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }

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

        measurementsChanged(); // 최신 측정값 Observer들에게 갱신 값 보내주기.
    }
}

'기타 > 디자인패턴' 카테고리의 다른 글

[Design Pattern] Command Pattern  (2) 2024.06.03
[Design Pattern] Singleton Pattern  (0) 2024.05.31
[Design Pattern] Factory Pattern  (0) 2024.05.29
[Design Pattern] Decorator Pattern  (0) 2024.05.28
[Design Pattern] Strategy Pattern  (0) 2024.05.27

+ Recent posts