[해결] HeadfirstDesignPatterns에 나오는 옵저버 패턴과 관련해서...

GunSmoke의 이미지

Headfirst Design Patterns로 패턴에 막 입문했습니다.

2장에서 옵저버 패턴 관련해서 기상 스테이션 예제가 나오는데요. 다음과 같이 자바 내장 옵저버 패턴을 활용해서 Pull 방식으로 예제를 수정합니다.

Observable을 확장한 주제, WeatherData 클래스입니다. 예전 Push 방식일 때는 notifyObservers() 메소드에서 옵저버들의 update() 메소드를 직접 호출하여 데이터를 전달했습니다. 그러나 지금은 아무 인자 없이 호출하여 옵저버에서 update() 메소드가 자동으로 호출되도록 하죠.

import java.util.Observable;
import java.util.Observer;
 
public class WeatherData extends Observable{
 
    private float temperature;
    private float humidity;
    private float pressure;
 
    public WeatherData(){
    }
 
    public void measurementsChanged(){
        setChanged();
        notifyObservers();
    }
 
    public void setMeasurements(float temperature, float humidity, float pressure){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
 
    public float getTemperature(){
        return temperature;
    }
 
    public float getHumidity(){
        return humidity;
    }
 
    public float getPressure(){
        return pressure;
    }
 
}

옵저버 중 하나인 CurrentConditionDisplay 클래스입니다. 역시 내장 Observer를 사용합니다. Observable 클래스의 notifyObservers()가 호출되면 자동으로 update()메소드가 응답하여 주제(Subject)의 데이터를 얻어옵니다.

import java.util.Observable;
import java.util.Observer;
 
public class CurrentConditionDisplay implements Observer, DisplayElement{
 
    Observable observable;
    private float temperature;
    private float humidity;
 
    public CurrentConditionDisplay(Observable observable){
 
        this.observable = observable;
        observable.addObserver(this);
    }
 
    public void update(Observable obs, Object arg){
        if(obs instanceof WeatherData){
            WeatherData weatherData = (WeatherData)obs;
            this.temperature = weatherData.getTemperature();
            this.humidity = weatherData.getHumidity();
            display();
        }
    }
 
    public void display(){
        System.out.println("Current conditions: "+temperature+"F degrees and "+humidity+"% humidity");
    }
}

그럼 질문 나갑니다.

제가 궁금했던 점은... 내장 옵저버 패턴을 사용하려면 Pull 방식 밖에 사용할 수 없는가 하는 부분이었습니다. 그래서 예제를 Push 방식으로 고쳐보기로 했습니다. 본문에는 Push 방식이라면 notifyObservers()에 Object를 넣어 옵저버로 전달하면 된다기에(일단 뭔가를 밀어넣어야 할테니 말이죠...) 다음과 같이 WeatherData 객체 자신을 그대로 전달했습니다.

    public void measurementsChanged(){
        setChanged();
        notifyObservers(this);
    }

그리고 옵저버의 update() 역시 주제가 전달하는 Object인 WeatherData를 받기 위해 다음과 같이 수정했습니다.

    public void update(Observable obs, Object arg){
        if(obs instanceof WeatherData){
            WeatherData weatherData = (WeatherData)arg;
	    this.temperature = weatherData.getTemperature();
	    this.humidity = weatherData.getHumidity();
	    display();
    ...
        }
    }

프로그램은 잘 수행되는데요. 제가 수정한 내용으로 Pull/Push 방식 전환이 제대로 이루어졌는지 궁금합니다.

violino의 이미지

한글판 번역이 재미있네요. Subject를 주제라..

암튼, 어떻게 하는지는 제대로 이해하신 것 같습니다.
다만, 지금의 구현방식으론 obs와 arg가 모두 같은 놈이라 별 차이가 보이지 않겠죠.
temperature, humidity 를 따로 떼어내서 data class를 하나 만드시든가,
temperature, humidity 클래스들을 따로 따로 만들어서 모두 observable로 하는 방법들이 있을 듯 하네요.
(그래봐야 이 예제에선 많이 다르진 않습니다)
notifyObservers(obj)할때 obj에 실질적인 정보가 채워져 있을때 의미가 있겠죠.
예를들어, obj가 뉴스 헤드라인 문자열(목록)이라고 하면 이해하기 쉽겠지요.
push를 했는데, subject에 다시 접근한다는게 좀 그렇거든요.

근데, 이 책에서 설명하는 자바 observable 인터페이스의 push나 pull 방식 구별이 별로 맘에 들진 않네요.
디자인패턴에서 Observer 패턴의 개념은 push 방식이거든요.
원래 pull 방식이라고 하면 observer가 필요에 따라 (또는 주기적으로) subject의 정보를 긁어오는걸 말하는게 보통이죠.
암튼, 좋은 책을 교재로 찾으셨네요.
부족하지만 제 위키에도 그 책을 기반으로 해서 세미나한 자료들이 몇개 있습니다.
참고하시길..

vio:

GunSmoke의 이미지

답변감사합니다!

저도 처음에는 temperature와 humidity를 하나로 묶어서.....

네...맞아요.

구조체를 만들려고 했습니다. ㅠㅠ

어쨌든 또다른 클래스로 만들어서 보낼 생각을 했습니다만 너무 복잡해지는 것 같아 그만뒀습니다.

옵저버 패턴이 기본적으로 push 방식이라는 사실 잘 알았습니다. 감사합니다.

大逆戰

大逆戰

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.