每日一得

不求多得,只求一得 about java,hibernate,spring,design,database,Ror,ruby,快速开发
最近关心的内容:SSH,seam,flex,敏捷,TDD
本站的官方站点是:颠覆软件

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  220 随笔 :: 9 文章 :: 421 评论 :: 0 Trackbacks
key words: 观察者模式 Observer模式

definition:
defines a one-to-many dependency between objects so that when one object changes state,all of its dependents are notified and updated automatically.

物理模型:
观察者注册
observerpattern_02.gif

观察者通知:
observerpattern_03.gif
观察者撤销注册
observerpattern_04.gif

business: weather station
天气预报,在预报的数据更新后自动通知到各类不同显示类型的终端,前提是这些终端向预报中心注册了预定服务(register the service),这一点类似于订阅报纸,你'订阅'了以后就可以呆在家等邮递员给你送过来.
看一下类图:weather.png


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

public class WeatherData implements Subject {
    
private ArrayList observers;
    
private float temperature;
    
private float humidity;
    
private float pressure;
    
    
public WeatherData() {
        observers 
= new ArrayList();
    }
    
    
public void registerObserver(Observer o) {
        observers.add(o);
    }
    
    
public void removeObserver(Observer o) {
        
int i = observers.indexOf(o);
        
if (i >= 0) {
            observers.remove(i);
        }
    }
    
    
public void notifyObservers() {
        
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);
}


public interface DisplayElement {
    
public void display();
}

public class CurrentConditionsDisplay implements Observer, DisplayElement {
    
private float temperature;
    
private float humidity;
    
private Subject weatherData;
    
    
public CurrentConditionsDisplay(Subject 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");
    }
}

public class WeatherStation {

    
public static void main(String[] args) {
        WeatherData weatherData 
= new WeatherData();
   
        //register to weatherData(subscribe to weatherData)
        CurrentConditionsDisplay currentDisplay 
=new CurrentConditionsDisplay(weatherData);
        StatisticsDisplay statisticsDisplay 
= new StatisticsDisplay(weatherData);
        ForecastDisplay forecastDisplay 
= new ForecastDisplay(weatherData);

        weatherData.setMeasurements(
806530.4f);
        weatherData.setMeasurements(
827029.2f);
        weatherData.setMeasurements(
789029.2f);
    }
}


public class WeatherStationHeatIndex {

    
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);
        HeatIndexDisplay heatIndexDisplay 
= new HeatIndexDisplay(weatherData);

        weatherData.setMeasurements(
806530.4f);
        weatherData.setMeasurements(
827029.2f);
        weatherData.setMeasurements(
789029.2f);
    }
}


other places to use Observe-Pattern in JDK:

public class SwingObserverExample {
    JFrame frame;
    
    
public static void main(String[] args) {
        SwingObserverExample example 
= new SwingObserverExample();
        example.go();
    }
    
    
public void go() {
        frame 
= new JFrame();

        JButton button 
= new JButton("Should I do it?");
        //register to AngelListener and DevilListener

        button.addActionListener(
new AngelListener());
        button.addActionListener(
new DevilListener());
        frame.getContentPane().add(BorderLayout.CENTER, button);

        
// Set frame properties 
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(BorderLayout.CENTER, button);
        frame.setSize(
300,300);
        frame.setVisible(
true);
    }
    
    
class AngelListener implements ActionListener {
        
public void actionPerformed(ActionEvent event) {
            System.out.println(
"Don't do it, you might regret it!");
        }
    }

    
class DevilListener implements ActionListener {
        
public void actionPerformed(ActionEvent event) {
            System.out.println(
"Come on, do it!");
        }
    }
}



implement it with java built-in Observe-Pattern
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;
    }
}






增加一个看到的通俗版的解说:

观察者模式 Observer Pattern — 三国演义之超级间谍战 — 美女貂蝉的故事

说明:我也是初学者,希望大家能提出宝贵意见。另外转载请注明作者左光和出处博客园,毕竟花费了很长时间才完成。

情节:

这一次讲的故事情节很简单,但是充满了谋略和斗争。大体意思就是三国初期,曹刘孙三家在徐州联手消灭了吕布,但是自己也伤了元气。而此时袁术得了传国玉玺,在淮南称帝,兵精将广,图谋不轨,对三家威胁都很大。于是曹刘孙三家在一起开了个会,决定派遣一名超级间谍打入到袁术身旁,监视他的一举一动,这样的话一旦袁术想干什么坏事,他们就可以立刻知道并做出相应的调整,知己知彼百战百胜嘛。

计是好计,问题是派谁去当这个超级间谍呢?正当大家愁眉苦脸的时候,美女貂蝉自告奋勇,想当年董卓那么厉害都让 我灭了,何况一个小小的袁术呢?大家一听,说的有理,于是就把貂蝉献给了袁术当了妃子。另外三家还各派出一名小奸细常住在淮南城内,他们的任务是当联络 员,貂蝉有什么情报总不能自己曹刘孙三家挨个跑着送吧?直接丢给各国联络员,然后让他们通知各自的主公就 OK 了!而三家只要一接到各自奸细的通知,就会立即做出反应。

还有一个小插曲,袁术虽然收下了貂蝉,但是对她看管很严,大大方方地把情报送出去不太可能,逼不得以,貂蝉自己设计了一套密码来传递情报,虽然加密 方法没有公开,但是她想总有人可以破解了吧?没错,对诸葛亮来说就是小菜一碟,从此袁术穿什么内裤曹刘孙三家都知道得清清楚楚。

分析:

下面我们用 观察者模式  来分析一下上面这个故事

1、美女貂蝉:貂蝉在观察者模式中叫做被观察者(Subject),主要任务是独立的管理后台数据和业务逻辑,同时尽可能不受前台客户端界面变化的影响。当然,还要负责登记或者注销各个观察者。

在这个故事里,貂蝉仅仅维护了一个数据 ,就是情报 —  私有变量 info ;另外还拥有一个业务逻辑,是用来加密 info 的方法 Reverse(string str) 。每次得到新的情报,她就会先加密,然后立刻找到在自己这登记过的联络员,让这些联络员通知自己的主公应变。

情报一旦发送出去, 貂蝉的任务就算完成了,具体曹刘孙三家怎么应对,是打是降还是另有其他方法,那是三家自己的事情,和她貂蝉就没什么关系了。

2、曹刘孙三家:曹刘孙三家在观察者模式里叫做观察者,主要任务就是从界面上用“各种方式”即时的反映出 被观察者,所谓“各种方式”就是说用字符、图形、声音都可以表示同样数据,外在表现不同而已,本质都是一些数据。所谓“即时”,就是说只要 被观察者 发生变化, 观察者 也会立刻跟着变化,用行话应该叫做刷新 Update吧。

在这个故事里,我们可以看到运行结果中,每次貂蝉有什么新的情报,三家都会在屏幕上显示出来,虽然很简单,但 他们确实是用各自不同的方式表示了同样的数据








posted on 2006-08-07 20:07 Alex 阅读(442) 评论(0)  编辑  收藏 所属分类: design

只有注册用户登录后才能发表评论。


网站导航: