模式定義
觀察者模式(Observer Pattern):觀察者模式定義對(duì)象間的一種一對(duì)多依賴關(guān)系赚爵,使得每當(dāng)一個(gè)對(duì)象狀態(tài)發(fā)生改變時(shí),其相關(guān)依賴的對(duì)象皆得到通知并且被自動(dòng)更新粟耻。不過觀察者只能知道目標(biāo)發(fā)送了改變试读,而不能知道具體怎么改變的。
觀察者角色
觀察者模式包含如下角色:
Subject:目標(biāo)
ConcreteSubject:具體目標(biāo)
Observer:觀察者
ConcreteObserver:具體觀察者
Observer模式”push”和”pull”數(shù)據(jù)
具體Subject可以通過兩種方式通知具體觀察者更新數(shù)據(jù):
①push數(shù)據(jù)方式:具體Subject將變化后的數(shù)據(jù)全部交給具體觀察者;
②pull數(shù)據(jù)方式:具體Subject提供獲得數(shù)據(jù)的方法,具體觀察者調(diào)用具體主題提供的方法獲得數(shù)據(jù)训裆。
典型列子
PS:代碼例子來自《圖說設(shè)計(jì)模式》
抽象目標(biāo)類
import java.util.*;
public abstract class Subject
{
protected ArrayList observers = new ArrayList();
public abstract void attach(Observer observer);
public abstract void detach(Observer observer);
public abstract void notify();
}
具體目標(biāo)類
public class ConcreteSubject extends Subject
{
public void attach(Observer observer)
{
observers.add(observer);
}
public void detach(Observer observer)
{
observers.remove(observer);
}
public void notify()
{
for(Object obs:observers)
{
((Observer)obs).update();
}
}
}
抽象觀察者類
public interface Observer
{
public void update();
}
具體觀察者類
public class ConcreteObserver implements Observer
{
public void update()
{
//具體更新代碼
}
}
還有一個(gè)不錯(cuò)的例子可以參考《Head First 設(shè)計(jì)模式》里的氣象局例子
模式優(yōu)缺點(diǎn)
觀察者優(yōu)點(diǎn):下面簡(jiǎn)要描述一下,觀察者可以實(shí)現(xiàn)表現(xiàn)層和數(shù)據(jù)邏輯層的分離蜀铲;觀察者模式在觀察目標(biāo)和觀察者之間建立一個(gè)抽象的耦合
觀察者缺點(diǎn):如果觀察者類和目標(biāo)類之間有循環(huán)關(guān)聯(lián)边琉,很容易導(dǎo)致系統(tǒng)奔潰;如果觀察者太多的話记劝,通知所有的觀察者將花費(fèi)很多時(shí)間
模式應(yīng)用
Swing变姨、RMI、JDK內(nèi)置的java.util.Observer接口和java.util.Observable類都是觀察者模式的應(yīng)用
經(jīng)典氣象局例子
PS:本列子來自《Head First 設(shè)計(jì)模式》
自己看《Head First設(shè)計(jì)模式》厌丑,本博客僅僅是自己做做筆記
下面的例子來自《Head First設(shè)計(jì)模式》一書定欧,推薦讀者去學(xué)習(xí)
[圖片上傳失敗...(image-e24d0-1532252388825)]
主題接口,定義一個(gè)主題接口
public interface Subject {
//注冊(cè)觀察者
public void registerObserver(Observer o);
//remove觀察者
public void removeObserver(Observer o);
//通知觀察者
public void notifyObservers();
}
weatherDate類怒竿,其實(shí)就是主題接口的實(shí)現(xiàn)類砍鸠,weatherData類實(shí)現(xiàn)Subject接口,主要用來注冊(cè)觀察者耕驰,通知觀察者等等爷辱,當(dāng)數(shù)據(jù)變化時(shí),即時(shí)通知注冊(cè)的觀察者,代碼實(shí)現(xiàn)是通過循環(huán)遍歷饭弓,觀察者再調(diào)用更新數(shù)據(jù)接口來實(shí)現(xiàn)双饥,《Head First設(shè)計(jì)模式》一書提供了基于JDK的內(nèi)置類來實(shí)現(xiàn)的列子,讀者可以去看看
import java.util.ArrayList;
public class WeatherData implements Subject {
private ArrayList observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList();//實(shí)例對(duì)象弟断,通過數(shù)組列表來存在觀察者對(duì)象
}
public void registerObserver(Observer o) {
observers.add(o);//注冊(cè)觀察者
}
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i >= 0) {
observers.remove(i);//remove觀察者對(duì)象
}
}
public void notifyObservers() {//循環(huán)遍歷咏花,通知所有注冊(cè)的觀察者
for (int i = 0; i < observers.size(); i++) {
Observer observer = (Observer)observers.get(i);
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();
}
// other WeatherData methods here
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
public float getPressure() {
return pressure;
}
}
觀察者接口類
public interface Observer {
public void update(float temp, float humidity, float pressure);
}
觀察者接口實(shí)現(xiàn)類
public interface DisplayElement {
public void display();
}
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
public CurrentConditionsDisplay(Subject weatherData) {
weatherData.registerObserver(this);//注冊(cè)觀察者
}
/更新數(shù)據(jù)
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");
}
}
控制臺(tái)打印一下
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay =
new CurrentConditionsDisplay(weatherData);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}