加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

设计模式之观察者模式

发布时间:2020-12-13 20:55:41 所属栏目:百科 来源:网络整理
导读:情景: 气象站会实时发布气象数据,要求创建布告板,并把气象站发布的数据显示出来。 布告板会有很多,随时回添加一个或删除一个,而每个布告板显示的格式也不尽相同。 观察者模式:定义了对象之间的一对多的依赖,这样一来,当一个对象改变状态时,它的所有

情景:

气象站会实时发布气象数据,要求创建布告板,并把气象站发布的数据显示出来。

布告板会有很多,随时回添加一个或删除一个,而每个布告板显示的格式也不尽相同。

观察者模式:定义了对象之间的一对多的依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

被观察对象称作主题(Subject),依赖主题的对象称作观察者(Observer)。

当两个对象之间松耦合,它们依然可以交互,但是不太清除彼此之间的细节。

观察者模式提供了一种对象设计,让主题和观察者之间松耦合。

类图:?

设计原则:为了交互对象之间的松耦合设计而努力。

气象站的实现:

主题接口:

观察者接口:

update( temp, humidity,

主题(气象站)实现:

<span style="color: #0000ff;">public <span style="color: #0000ff;">class WeatherData <span style="color: #0000ff;">implements<span style="color: #000000;"> Subject {

</span><span style="color: #0000ff;"&gt;private</span> ArrayList<Observer><span style="color: #000000;"&gt; observers;
</span><span style="color: #0000ff;"&gt;private</span> <span style="color: #0000ff;"&gt;float</span><span style="color: #000000;"&gt; temperature;
</span><span style="color: #0000ff;"&gt;private</span> <span style="color: #0000ff;"&gt;float</span><span style="color: #000000;"&gt; humidity;
</span><span style="color: #0000ff;"&gt;private</span> <span style="color: #0000ff;"&gt;float</span><span style="color: #000000;"&gt; pressure;

</span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; WeatherData() {
    observers </span>= <span style="color: #0000ff;"&gt;new</span> ArrayList<><span style="color: #000000;"&gt;();
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; registerObserver(Observer o) {
    observers.add(o);
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; removeObserver(Observer o) {
    </span><span style="color: #0000ff;"&gt;int</span> i =<span style="color: #000000;"&gt; observers.indexOf(o);
    </span><span style="color: #0000ff;"&gt;if</span> (i >= 0<span style="color: #000000;"&gt;) {
        observers.remove(i);
    }
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; notifyObservers() {
    </span><span style="color: #0000ff;"&gt;for</span> (<span style="color: #0000ff;"&gt;int</span> i = 0; i < observers.size(); i++<span style="color: #000000;"&gt;) {
        Observer observer </span>=<span style="color: #000000;"&gt; observers.get(i);
        observer.update(temperature,humidity,pressure);
    }
}

</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; measurementsChanged() {
    notifyObservers();
}

</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span> setMeasurements(<span style="color: #0000ff;"&gt;float</span> temperature,<span style="color: #0000ff;"&gt;float</span><span style="color: #000000;"&gt; pressure) {
    </span><span style="color: #0000ff;"&gt;this</span>.temperature =<span style="color: #000000;"&gt; temperature;
    </span><span style="color: #0000ff;"&gt;this</span>.humidity =<span style="color: #000000;"&gt; humidity;
    </span><span style="color: #0000ff;"&gt;this</span>.pressure =<span style="color: #000000;"&gt; pressure;
    measurementsChanged();
}

}

观察者(布告板)实现:

<span style="color: #0000ff;">public <span style="color: #0000ff;">class CurrentConditionsDisplay <span style="color: #0000ff;">implements<span style="color: #000000;"> Observer,DisplayElement {

</span><span style="color: #0000ff;"&gt;private</span> <span style="color: #0000ff;"&gt;float</span><span style="color: #000000;"&gt; temperature;
</span><span style="color: #0000ff;"&gt;private</span> <span style="color: #0000ff;"&gt;float</span><span style="color: #000000;"&gt; humidity;
</span><span style="color: #0000ff;"&gt;private</span><span style="color: #000000;"&gt; Subject weatherData;

</span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; CurrentConditionsDisplay(Subject weatherData) {
    </span><span style="color: #0000ff;"&gt;this</span>.weatherData =<span style="color: #000000;"&gt; weatherData;
    weatherData.registerObserver(</span><span style="color: #0000ff;"&gt;this</span><span style="color: #000000;"&gt;);
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; display() {
    System.out.println(</span>"Current conditions: " + temperature + 
            "F degrees and " + humidity + "% humdity."<span style="color: #000000;"&gt;);
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span> update(<span style="color: #0000ff;"&gt;float</span> temperature,<span style="color: #0000ff;"&gt;float</span><span style="color: #000000;"&gt; pressure) {
    </span><span style="color: #0000ff;"&gt;this</span>.temperature =<span style="color: #000000;"&gt; temperature;
    </span><span style="color: #0000ff;"&gt;this</span>.humidity =<span style="color: #000000;"&gt; humidity;
    display();
}

}
……………………
<span style="color: #0000ff;">public <span style="color: #0000ff;">class ChineseDisplay <span style="color: #0000ff;">implements<span style="color: #000000;"> Observer,DisplayElement {
<span style="color: #0000ff;">private <span style="color: #0000ff;">float<span style="color: #000000;"> temperature;
<span style="color: #0000ff;">private <span style="color: #0000ff;">float<span style="color: #000000;"> humidity;
<span style="color: #0000ff;">private <span style="color: #0000ff;">float<span style="color: #000000;"> pressure;
<span style="color: #0000ff;">private<span style="color: #000000;"> Subject weatherData;

</span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; ChineseDisplay(Subject data) {
    </span><span style="color: #0000ff;"&gt;this</span>.weatherData =<span style="color: #000000;"&gt; data;
    weatherData.registerObserver(</span><span style="color: #0000ff;"&gt;this</span><span style="color: #000000;"&gt;);
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; display() {
    System.out.println(</span>"天气状况: 气温:" + temperature + 
            "F, 湿度:" + humidity + "%, 气压:" + pressure + " Pa。"<span style="color: #000000;"&gt;);
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span> update(<span style="color: #0000ff;"&gt;float</span> temperature,<span style="color: #0000ff;"&gt;float</span><span style="color: #000000;"&gt; pressure) {
    </span><span style="color: #0000ff;"&gt;this</span>.temperature =<span style="color: #000000;"&gt; temperature;
    </span><span style="color: #0000ff;"&gt;this</span>.humidity =<span style="color: #000000;"&gt; humidity;
    </span><span style="color: #0000ff;"&gt;this</span>.pressure =<span style="color: #000000;"&gt; pressure;
    display();
}

}

测试类:

</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;static</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; main(String[] args) { WeatherData weatherData </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; WeatherData(); CurrentConditionsDisplay conditionsDisplay </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; CurrentConditionsDisplay(weatherData); StatisticsDisplay statisticsDisplay </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; StatisticsDisplay(weatherData); ChineseDisplay chineseDisplay </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; ChineseDisplay(weatherData); weatherData.setMeasurements(</span>80,65,30.4f<span style="color: #000000;"&gt;); System.out.println(); weatherData.setMeasurements(</span>82,70,29.2f<span style="color: #000000;"&gt;); System.out.println(); weatherData.setMeasurements(</span>78,90,29.2f<span style="color: #000000;"&gt;); }

}

输出:

Current conditions: 80.0F degrees and 65.0%80.0F, 湿度:65.0%, 气压:30.4Current conditions: 82.0F degrees and 70.0%<span style="color: #000000;"> humdity.
天气状况: 气温:
82.0F, 湿度:70.0%, 气压:29.2 Pa。

Java中自带Observable类和Observer类,可以通过继承这两个类来实现观察者模式

主题:

<span style="color: #0000ff;">public <span style="color: #0000ff;">class WeatherData <span style="color: #0000ff;">extends<span style="color: #000000;"> Observable {
<span style="color: #0000ff;">private <span style="color: #0000ff;">float<span style="color: #000000;"> temperature;
<span style="color: #0000ff;">private <span style="color: #0000ff;">float<span style="color: #000000;"> humidity;
<span style="color: #0000ff;">private <span style="color: #0000ff;">float<span style="color: #000000;"> pressure;

</span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; WeatherData() {}

</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; measurementsChanged() {
    setChanged();
    notifyObservers();
}

</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span> setMeasurements(<span style="color: #0000ff;"&gt;float</span> temperature,<span style="color: #0000ff;"&gt;float</span><span style="color: #000000;"&gt; pressure) {
    </span><span style="color: #0000ff;"&gt;this</span>.temperature =<span style="color: #000000;"&gt; temperature;
    </span><span style="color: #0000ff;"&gt;this</span>.humidity =<span style="color: #000000;"&gt; humidity;
    </span><span style="color: #0000ff;"&gt;this</span>.pressure =<span style="color: #000000;"&gt; pressure;
    measurementsChanged();
}

</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;float</span><span style="color: #000000;"&gt; getTemperature() {
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; temperature;
}

</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;float</span><span style="color: #000000;"&gt; getHumidity() {
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; humidity;
}

</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;float</span><span style="color: #000000;"&gt; getPressure() {
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; pressure;
}

}

观察Observable源码setChanged方法

=

有时候改变需要自己定义,比如温度改变0.5℃以上才算改变等……

notifyObservers方法的实现:

</span><span style="color: #0000ff;"&gt;synchronized</span> (<span style="color: #0000ff;"&gt;this</span><span style="color: #000000;"&gt;) { </span><span style="color: #0000ff;"&gt;if</span> (!<span style="color: #000000;"&gt;changed) </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt;; arrLocal </span>=<span style="color: #000000;"&gt; obs.toArray(); clearChanged(); } </span><span style="color: #0000ff;"&gt;for</span> (<span style="color: #0000ff;"&gt;int</span> i = arrLocal.length-1; i>=0; i--<span style="color: #000000;"&gt;) ((Observer)arrLocal[i]).update(</span><span style="color: #0000ff;"&gt;this</span><span style="color: #000000;"&gt;,arg); }</span></pre>

布告板的实现:

<span style="color: #0000ff;">public <span style="color: #0000ff;">class CurrentConditionsDisplay <span style="color: #0000ff;">implements<span style="color: #000000;"> Observer,DisplayElement {

</span><span style="color: #0000ff;"&gt;private</span><span style="color: #000000;"&gt; Observable observable;
</span><span style="color: #0000ff;"&gt;private</span> <span style="color: #0000ff;"&gt;float</span><span style="color: #000000;"&gt; temperature;
</span><span style="color: #0000ff;"&gt;private</span> <span style="color: #0000ff;"&gt;float</span><span style="color: #000000;"&gt; humidity;

</span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; CurrentConditionsDisplay(Observable observable) {
    </span><span style="color: #0000ff;"&gt;this</span>.observable =<span style="color: #000000;"&gt; observable;
    observable.addObserver(</span><span style="color: #0000ff;"&gt;this</span><span style="color: #000000;"&gt;);
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; display() {
    System.out.println(</span>"Current conditions: " + temperature + 
            "F degrees and " + humidity + "% humdity."<span style="color: #000000;"&gt;);
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; update(Observable obs,Object arg) {
    </span><span style="color: #0000ff;"&gt;if</span> (obs <span style="color: #0000ff;"&gt;instanceof</span><span style="color: #000000;"&gt; WeatherData) {
        WeatherData weatherData </span>=<span style="color: #000000;"&gt; (WeatherData) obs;
        </span><span style="color: #0000ff;"&gt;this</span>.temperature =<span style="color: #000000;"&gt; weatherData.getTemperature();
        </span><span style="color: #0000ff;"&gt;this</span>.humidity =<span style="color: #000000;"&gt; weatherData.getHumidity();
        display();
    }
}

}

这里的update()方法和上面的实现不同,上面的实现是push的方法,也就是主题把数据直接送到观察者那里。而这里的是观察者通过getter()方法来自己pull所需要的数据。

但是java.util.Observable和java.util.Observer都是类而不是接口,所以要继承它们就无法继承别的类了。

JDK中的观察者模式

Swing中的JButton就用到了观察者模式。

<span style="color: #0000ff;">import<span style="color: #000000;"> javax.swing.JButton;
<span style="color: #0000ff;">import
<span style="color: #000000;"> javax.swing.JFrame;

<span style="color: #0000ff;">public <span style="color: #0000ff;">class<span style="color: #000000;"> SwingObserverExample {
JFrame frame;

</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;static</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; main(String[] args) {
    SwingObserverExample example </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; SwingObserverExample();
    example.go();
}

</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; go() {
    frame </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; JFrame();

    JButton button </span>= <span style="color: #0000ff;"&gt;new</span> JButton("Should I do it?"<span style="color: #000000;"&gt;);
    button.addActionListener(</span><span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; AngelListener());
    button.addActionListener(</span><span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; DevilListener());
    frame.getContentPane().add(BorderLayout.CENTER,button);
    frame.setSize(</span>200,200<span style="color: #000000;"&gt;);
    frame.setVisible(</span><span style="color: #0000ff;"&gt;true</span><span style="color: #000000;"&gt;);
}
</span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 一个ActionListener就是一个观察者</span>
<span style="color: #0000ff;"&gt;class</span> AngelListener <span style="color: #0000ff;"&gt;implements</span><span style="color: #000000;"&gt; ActionListener {
    @Override
    </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; actionPerformed(ActionEvent e) {
        System.out.println(</span>"Dont do it,you might regret it!"<span style="color: #000000;"&gt;);
    }
}


</span><span style="color: #0000ff;"&gt;class</span> DevilListener <span style="color: #0000ff;"&gt;implements</span><span style="color: #000000;"&gt; ActionListener {
    @Override
    </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; actionPerformed(ActionEvent e) {
        System.out.println(</span>"Come on,do it!"<span style="color: #000000;"&gt;);
    }
}

}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读