본문 바로가기
Programming/디자인 패턴

옵저버 패턴 (Observer)

by Teshub 2021. 1. 29.

- 정의 -

한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다 의존성을 정의합니다

 

옵저버 패턴의 경우 신문구독을 생각하면 이해하기 쉽습니다

신문이 발행(객체의 정보 변경)되면 그 정보가 다른 객체들 에게 전달되는 구조라 생각하시면 됩니다

 

자바에서의 옵저버 패턴을 이용하지 않고 직접 옵저버패턴을 구현하는 다이어그램입니다 ;

 

아래는 예시 코드입니다

인터페이스 코드들입니다

public interface Subject {
	
    //옵저버를 등록하고 제거하는 역할의 메서드
    public void registerObserver(ObserverH o);
    public void removeObserver(ObserverH o);
    
    //주제 객체의 상태가 변경되었을때 모든 옵저버들에게 알리기위해 호출되는 메서드
    public void notifyObservers();

}

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

public interface DisplayElement {
    public void display();
}

 

구현 클래스 부분 코드입니다

public class WeatherData implements Subject{

    private ArrayList observers;
    private float temperature;
    private float humidity;
    private float pressure;

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

    //subject의 인터페이스를 구현하는 코드
    @Override
    public void registerObserver(ObserverH o) {
        observers.add(o);
    }

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

    @Override
    public void notifyObservers() {
        for (int i = 0; i < observers.size(); i++) {
            ObserverH observerH = (ObserverH) observers.get(i);
            observerH.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();

    }
}
public class CurrentConditionsDisplay implements ObserverH, DisplayElement{

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

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

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

    }

    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }
    //옵저버객체에서 삭제한후를 보려고 작성한코드입니다
    public void removeOb(Subject weatherData){
        this.weatherData = weatherData;
        weatherData.removeObserver(this);
    }

}

 

일대다 정의를 위해 ArrayList로 옵저버를 관리합니다

테스트 코드에선 주제를 받아야 하는 클래스가 생성 시 생성자로 옵저버에 등록을 되게 코드를 구성하였습니다

테스트 코드입니다

public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();

        CurrentConditionsDisplay currentConditionsDisplay =
                new CurrentConditionsDisplay(weatherData);

        weatherData.setMeasurements(80, 60, 30.4f);
        weatherData.setMeasurements(50, 42, 29.0f);
        
        //옵저버 삭제후 작동하는지
        currentConditionsDisplay.removeOb(weatherData);
        weatherData.setMeasurements(33, 12, 26.3f);
    }
}

 

 

 

실행 결과입니다

주제 객체의 정보를 set으로 수정 시 CurrentConditionsDisplay에 정보가 전달됩니다

옵저버가 삭제된 후에는 CurrentConditionsDisplay의 display() 메서드가 실행되지 않았습니다

 

이런 옵저퍼 패턴의 방식을 푸시(push)라고 합니다

주제 객체가 변경될 때마다 observer로 데이터를 전달합니다

 

자바에서도 observer클래스로 옵저버패턴을 지원하지만 인터페이스가 아닌 클래스로 되어있어 상속을 받아야 하기 때문에 다중 상속을 지원하지 않는 자바에서는 옵저버패턴이 필용한클래스가 다른 클래스를 상속받아야 하는 경우 사용이 불가능한 걸로 알고 있습니다(추후 확인 후 수정하겠습니다)

 

참고서적 : Head First Design Patterns

 

책을 참고하였지만 직접내용을 치고 구현한 것이라 오류나 오탈자가 있을 수 있습니다.

틀린 내용 있을 시 덧글에 적어주시면 참고하여 수정하겠습니다 감사합니다.

 

다음 포스팅은 데코레이터 패턴입니다

 

 

728x90

댓글