现在是大三寒假,在大二暑假时进入国内某互联网上市公司做Android开发,半年多的学习和工作积累了很多,刚好现在下班后不用急的赶回去上课,就留在公司写博客总结一下。《设计模式》这本经典的书是之前在公交车上读的,现在计划每隔一段时间总结一个专题,回顾一下。今天回顾一下第一个模式:观察者模式。由于本人能力有限,这也是本人写的第一篇博客,有错误的地方希望各位大神指点。
认识观察者模式
举一个生活中的例子,报社的业务是出版报纸,如果你向报社订阅了报纸,那么他们只要有新报纸出版,就会给你送来,如果你不想看了,可以取消订阅,那么他们就不会把报纸送来了。他们可以有很多个订阅者,只要报社在运营,就会一直有人想他们订阅或取消订阅报纸。
出版者+订阅者=观察者模式
如果你了解了的订阅是怎么回事,那么你就明白了观察者模式是怎么回事,在这里“出版者”被称为“主题”(Subject),“订阅者”被称为“观察者”(Observer)。
观察者模式
定义了对象之间的一对多依赖,当一个对象发生改变时,它所有的依赖者就会搜到通知,并自动更新。
模式中的角色
1.抽象主题角色(Subject):目标角色知道它的观察者,可以有任意多个观察者观察同一个目标。并且提供注册和删除观察者对象的接口。目标角色往往由抽象类或者接口来实现。
2. 抽象观察者角色(Observer):为那些在目标发生改变时需要获得通知的对象定义一个更新接口。抽象观察者角色主要由抽象类或者接口来实现。
3.具体主题角色(Concrete Subject):将有关状态存入各个Concrete Observer对象。当它的状态发生改变时, 向它的各个观察者发出通知。
4.具体观察者角色(Concrete Observer):存储有关状态,这些状态应与目标的状态保持一致。实现Observer的更新接口以使自身状态与目标的状态保持一致。在本角色内也可以维护一个指向Concrete Subject对象的引用。
实际工程项目中的应用
下面来结合一个实际工程项目:气象监测站会将传感器收集到的数据(温度Temperature,湿度Humidity,气压Pressure)传给WeatherData对象,利用该对象来实时更新显示三个布告板:目前天气状况(CurrentConditions),气象统计(Statistics)和天气预报(Forecast)。
观察者模式定义了一对多的依赖关系,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并更新。那么WeatherData类就是“一”,“多”就是使用天气观测的各种布告板。我们把WeatherData对象当做“主题(Subject)",把布告板当做观察者,布告板为了取得信息,向WeatherData对象注册。一旦WeatherData对象知道某个布告板的存在,就会调用update方法,来对布告板进行更新。update是在观察者Observer接口中定义的。
类图
实现代码
主题Subject接口:利用该接口中的函数可以注册,移除和通知观察者
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
观察者Observer接口:主题通过调用update方法来通知各个实现Observer接口的观察者们。
public interface Observer {
public void update(float temp,float humidity,float pressure);
}
具体主题角色(Concrete Subject)
</pre><pre name="code" class="java">public class WeatherData implements Subject{
private ArrayList observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData(){
observers=new ArrayList();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
int i=observers.indexOf(o);
if(i>=0){
observers.remove(i);
}
}
@Override
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();
}
}
具体观察者角色CurrentConditionDisplay
public class CurrentConditionsDisplay implements Observer{
private float temperature;
private float humidity;
private float pressure;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData){
this.weatherData=weatherData;
weatherData.registerObserver(this);
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature=temp;
this.humidity=humidity;
this.pressure=pressure;
System.out.println("当前天气状态 :"+temperature+"度 , "+humidity+
"湿度 和 "+pressure+"帕");
}
}
具体观察者角色StatisticsDisplay
public class StatisticsDisplay implements Observer{
private float temperature;
private float humidity;
private float pressure;
private Subject weatherData;
public StatisticsDisplay(Subject weatherData){
this.weatherData=weatherData;
weatherData.registerObserver(this);
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature=temp;
this.humidity=humidity;
this.pressure=pressure;
System.out.println("统计天气显示 :"+temperature+"度 , "+humidity+
"湿度 和 "+pressure+"帕");
}
}
具体观察者角色ForecastDisplay
public class ForecastDisplay implements Observer{
private float temperature;
private float humidity;
private float pressure;
private Subject weatherData;
public ForecastDisplay(Subject weatherData){
this.weatherData=weatherData;
weatherData.registerObserver(this);
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature=temp;
this.humidity=humidity;
this.pressure=pressure;
System.out.println("预测天气显示 :"+temperature+"度 , "+humidity+
"湿度 和 "+pressure+"帕");
}
}
测试代码
public class WeatherStation {
public static void main(String []args){
//首先建立一个主题WeatherData对象
WeatherData weatherData=new WeatherData();
//创建3个布告板
CurrentConditionsDisplay currentDisplay=new CurrentConditionsDisplay(weatherData);
StatisticsDisplay statisticsDisplay=new StatisticsDisplay(weatherData);
ForecastDisplay forecastDisplay=new ForecastDisplay(weatherData);
//模拟气象测量
weatherData.setMeasurements(80,65, 30.4f);
}
}
输出结果
当前天气状态 :80.0度 , 65.0湿度 和 30.4帕
统计天气显示 :80.0度 , 65.0湿度 和 30.4帕
预测天气显示 :80.0度 , 65.0湿度 和 30.4帕
模式总结
观察者模式提供了一种对象设计,让主题和观察者之间松耦合。让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。 但是依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。因为主题在调用观察者的update方法时把内部的成员传给了观察者,而且对于不同的观察者可能需要不同的参数。Java内置了观察者模式,有推push和拉pull两种。后续会使用java内置的观察者模式来实现。