您的位置:首页 > 其它

Header First设计模式学习笔记——观察者模式

2014-04-14 21:36 351 查看
问题引入

生成一个公告板显示当时的天气状况,当天气状况发生改变的时候公告板可以实时的更新。

模式定义

定义对象之间的一对多的依赖,当一个对象改变状态时,它的所有依赖者都会自动收到通知并自动更新。

认识模式

该模式在生活中是很常见的。想想生活中的各种各样的检测系统,报警系统,一旦有重要事件发生时,有关系统总能及时的收到通知,这就是观察者模式。

问题解决

关于观察者模式,java实际上给了我们内置的支持(可以看出该模式还是很常用的吧!)但是我们经常会自己实现。为什么呢?我们后面会给出答案。

被观察者我们称之为主题(Subject),相应的有观察者(Observer)。

一、自定义实现

1) Subject,Observer我们都定义为接口

package my.oschina.net.design.observer.owndesign;

public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver();
}

public interface Observer {
void update(Subject sub);
}


2)实现Subject和Observer接口(主题与观察者的实现)

a)主题实现

package my.oschina.net.design.observer.finaldesign;

import java.util.ArrayList;

public class WeatherData implements Subject{

//被观测的指标数据
private float temp;
private float humidity;
private float pressure;

//维护一个订阅过的Observer列表
private ArrayList<Observer> Observers;

public WeatherData()
{
this.Observers = new ArrayList<Observer>();
}

@Override
//增加Observer
public void registerObserver(Observer o) {
// TODO Auto-generated method stub
Observers.add(o);
}

@Override
//移除部分Observer
public void removeObserver(Observer o) {
// TODO Auto-generated method stub
int i = Observers.indexOf(o);
if(i != -1)
Observers.remove(Observers.indexOf(o));
}

@Override
//通知订阅过的Observer
public void notifyObserver() {
// TODO Auto-generated method stub
for(Observer o : Observers)
{
o.update(this);
}
}

public void setStatus(float temp, float humidity, float pressure)
{
this.temp = temp;
this.humidity = humidity;
this.pressure = pressure;

statusChanged();
}

public void statusChanged()
{
notifyObserver();
}

float getTemp()
{
return temp;
}

float getHumidity()
{
return humidity;
}

float getPressure()
{
return pressure;
}
}


b)观察者实现

package my.oschina.net.design.observer.finaldesign;

public class CurrentConditionDisplay implements Observer,Display{

//接收被观测者发过来的数据
private float temp;
private float humidity;
private float pressure;
//保存这个主题对象,可能后续有退订的需求
private WeatherData weatherData;

public CurrentConditionDisplay(WeatherData weahterdata)
{
this.weatherData = weahterdata;
weatherData.registerObserver(this);
}

@Override
public void update(Subject sub) {
// TODO Auto-generated method stub

if(sub instanceof WeatherData)
{
WeatherData weatherdata = (WeatherData)sub;
this.temp = weatherdata.getTemp();
this.humidity = weatherdata.getHumidity();
this.pressure = weatherdata.getPressure();
}

display();
}

@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("Temp --> " + temp + "humidity --> " +humidity + "pressure -->" + pressure);
}

}


3)Test一下

package my.oschina.net.design.observer.finaldesign;

public class ObserverTest1 {

public static void main(String[] args) {
// TODO Auto-generated method stub
WeatherData weatherdata = new WeatherData();

CurrentConditionDisplay cc = new CurrentConditionDisplay(weatherdata);

weatherdata.setStatus(12, 12, 12);
weatherdata.setStatus(13, 13, 13);
weatherdata.setStatus(14, 14, 14);
}
}


4)结果截图



二、java内置实现

在java的java.util 包(pac1kage)中包含了最基本的Observable类(可观察,通过继承方式获得其方法和属性)和Observer接口(观察),对你没有看错,我也没有写错,的确是Observable类和Observer接口,他们类似与我们上述自己定义的Subject和Observer接口,由于是java内置,有的时候使用它们的话真的是挺简单的,因为有好多的功能java本身已经为我们写好了!

其实这里你已经可以明白这种内置实现的弊端了,对就是因为Observable是个类!在java中只支持单继承,所以啊,这就限制了继承他的类使用的灵活性!

java内置的不同

a)关于主题对象

当我们自定义观察者的时候当需要通知观察者的时候我们直接调用notifyO不servers()方法即可, 但是java内置的方法不是这样的,我们需要两步走:

1>调用setChanged()方法,标记状态已改变;

2>调用notifyObserver()方法,完成通知的工作。

深入-------->setChanged()

我们来看看Observable内部的实现

setChanged()
{
cahnged = true;
}

notifyObservers(Object arg)
{
if(cahnged)
{
for every obsrver on the list
{
call update(this, arg)
}
cahngd = false;
}
}

notifyObservers()
{
notifyObservers(null)
}


看到这里有人可能要问了:为什么要设置一个标志呢???仔细想想,假设你是公司老总,每天要批一系列文件,好了,现在秘书送来一份文件你批了,一分钟没到,又有新的文件产生了,秘书又送了过来,然后。。。然后。。。你受得了吗?你可能会对秘书说:小李啊,这个文件你给我每50份一批给我送过来,我一并批阅!有时候我们并不希望被观察者有一丝的变化马上就通知我们,我们可以等被观察者达到一定的程度的时候(比如说等温度上升5℃以内不必通知系统,一旦超过5℃就通知系统!)再通知我们,你可以想想这样好处很多!所以当达到标准,我们需要通知观察者的时候调用setChanged()方法还真是不错的哦!

b)关于观察者

update的方法略有不同update(Observable o, Object arg),第一个参数是主题本身,第二个参数为传入notifyObserver()的数据对象,没有为空。这里就来决定是由被观察者push数据,还是有观察者自己pull数据。

代码走起

1)被观察者实现(注意import相应的package)
package my.oschina.net.design.observer.javautil;

import java.util.Observable;
import java.util.Observer;
/**
* 这种方式有一个弊端就是说Observable是一个 类而不是一个接口因此它限制了这个类的使用
* @author Eswin
*
*/
public class WeatherData extends Observable{

//被观测的指标数据
private float temp;
private float humidity;
private float pressure;

public WeatherData(){}

public void setStatus(float temp, float humidity, float pressure)
{
this.temp = temp;
this.humidity = humidity;
this.pressure = pressure;

statusChanged();
}

public void statusChanged()
{
setChanged();
notifyObservers();
}

public float getTemp()
{
return temp;
}

public float getHumidity()
{
return humidity;
}

public float getPressure()
{
return pressure;
}

}


2)观察者实现
package my.oschina.net.design.observer.javautil;

import java.util.Observable;
import java.util.Observer;

import my.oschina.net.design.observer.owndesign.Display;

public class CurrentConditionDisplay implements Observer, Display{

private float temp;
private float humidity;
private float pressure;

private Observable observable;

public CurrentConditionDisplay(Observable observable)
{
this.observable = observable;
observable.addObserver(this);

}

@Override
public void update(Observable o, Object arg) {
// TODO Auto-generated method stub
if(o instanceof WeatherData)
{
WeatherData weatherdata = (WeatherData)o;
this.temp = weatherdata.getTemp();
this.humidity = weatherdata.getHumidity();
this.pressure = weatherdata.getPressure();
}

display();

}

@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("Temp --> " + temp + "humidity --> " +humidity + "pressure -->" + pressure);
}

}


3)Test一下

package my.oschina.net.design.observer.javautil;

public class ObserverTest2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
WeatherData weatherdata = new WeatherData();

CurrentConditionDisplay cc = new CurrentConditionDisplay(weatherdata);

weatherdata.setStatus(12, 12, 12);
weatherdata.setStatus(13, 13, 13);
weatherdata.setStatus(14, 14, 14);
}
}


4)结果截图



模式延伸
其实我们我们在编程的过程中有很多时候都运用到了观察者模式,想想Swing,还有JavaBean,还有RMI。
模式建议
1)要注意Observable这个类所带来的问题;

2)有必要的话自己实现Observable也就是主题,很简单(三个方法实现就可以了)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: