책너두 (헤드 퍼스트 디자인 패턴) 6일차 (~101p)

요약

  • 객체들에게 연락 돌리기 (옵저버 패턴) 계속
    • 옵저버 패턴의 정의
    • 옵저버 패턴의 구조
    • 느슨한 결합의 위력
    • 기상 스테이션 구현하기
    • Subject 인터페이스 구현하기
    • 디스플레이 요소 구현하기

메모

옵저버 패턴의 정의

📍 옵저버 패턴(Observer Pattern) : 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에게 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의존성을 정의함.
  • 주제와 옵저버로 일대다 관계가 정의됨.
    • 옵저버는 주제에 딸려있음.
  • 옵저버 패턴의 경우, 보통 주제 인터페이스와 옵저버 인터페이스가 들어있는 클래스 디자인으로 구현됨.

옵저버 패턴의 구조

  • 주제를 나타내는 Subject 인터페이스
    • 각 주제마다 여러개의 옵저버가 있을 수 있음.
    • 옵저버가 될 가능성이 있는 객체는 Observer 인터페이스를 구현해야 함.
      • update() 메소드를 구현해야 함.
      • 주체 상태가 바뀌면 해당 메소드를 호출함.
  • 주제 역할을 하는 구상 클래스는 Subject 인터페이스를 구현해야 함.

느슨한 결합의 위력

  • 느슨한 결합 : 객체들이 상호작용할 수는 있지만, 서로를 잘 모르는 관계임.
    • 유연성이 아주 좋아짐.
    • 옵저버 패턴이 느슨한 결합을 보여주는 훌륭한 예임.
  • 주제는 옵저버가 특정 인터페이스(Observer 인터페이스)를 구현한다는 사실만 암.
  • 옵저버는 언제든지 새로 추가할 수 있음.
  • 새로운 형식의 옵저버를 추가할 때도 주제를 변경할 필요가 전혀 없음.
  • 주제와 옵저버는 서로 독립적으로 재사용할 수 있음.
  • 주제나 옵저버가 달라져도 서로에게 영향을 미치지 않음.
📍 디자인 원칙 : 상호작용하는 객체 사이에는 가능하면 느슨한 결합을 사용해야 한다. 느슨하게 결합하면, 변경 사항이 생겨도, 무난히 처리할 수 있는 유연한 객체지향 시스템을 구축할 수 있음. 왜냐면 객체 사이의 상호 의존성을 최소화하기 때문

기상 스테이션 구현하기

public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObservers();
}

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

public interface DisplayElement {
    public void display();
}
  • 주제는 옵저버를 등록하고, 제거하는 역할을 가져야 함.
  • 주제 상태가 변경되면 모든 옵저버에게 변경 내용을 알리는 메소드를 구현해야 함.
  • 옵저버의 update 메소드인자는 기상 정보가 변경될 때 옵저버에게 전달되는 상태값임.

Subject 인터페이스 구현하기

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 removeObserver(Observer o) {
        observers.remove(o);
    }

    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature, humidity, pressure);
        }
    }

    public void measurementsChanged() {
        notifyObservers();
    }

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

    // 기타 WeatherData 메소드
}
  • WeatherData 는 주제의 구상 클래스임.
    • 온도, 습도, 기압과 옵저버 객체들을 가지고 있음.
  • 기상 스테이션에서 가상 데이터를 가져올 때, setMeasurements 메서드가 호출됨.
    • 그러면 새로운 측정 값이 갱신되고, 모든 옵저버에 notify 함.

디스플레이 요소 구현하기

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);
    }

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

    public void display() {
        System.out.println("Current conditions: " + temperature 
            + "F degrees and " + humidity + "% humidity");
    }
}
  • 옵저버 구상 클래스는 Observer 를 반드시 구현해야 함.
    • update가 호출되면 온도와 습도를 저장하고, display를 호출함.
  • update 메소드에 display 메소드를 호출하는 방법은 지금과 같이 간단한 경우에는 괜찮아 보임.
    • 하지만, 더 좋은 방법은 12장 모델-뷰-컨트롤러 패턴을 배울때 자세히 살펴봄.
  • 주제 레퍼런스를 저장하는 이유는 나중에 옵저버 목록에서 탈퇴할 때 유용하게 쓸 수 있음.

기상 스테이션 테스트

  • p97~98 참고

댓글

Designed by JB FACTORY