Observer Pattern(观察者模式)定义:

  在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。

  干说定义肯定没有举例理解的透彻。想到Observer Pattern(观察者模式)就来举个生活中的例子来帮助我们更好消化和理解其具体含义。

举例:  

  订阅杂志或者报纸,这里面有两个主角,一个是报纸杂志的供应商(报社),一个是报纸杂志的订阅者。这里就是被观察者也叫主题(供应商)和观察者(订阅者)。主题(Subject)应该有观察者名单,当主题有新的报纸售出时将按主体持有的观察者名单一个一个发送新报纸(发送没有先后顺序,一切按存储顺序发送)。

  同时主题还应该有三个方法:

    一、将观察者写入名单中(registerObserver())

    二、将观察者从名单中删除(removeObserver())

    三、当有新消息发送及时通知名单中所有观察者(notifyObservers())

 public interface Subject {//主题接口,所有报社都要实现该接口

     /*没有存储订阅者的列表,是因为我们不想在接口中写死存储方式,
让编程人员自己在实现接口的时候写入想要的存储方式(如:链表,数组,栈,队列等)
这样更合理。*/ public void registerObserver(Observer o);//将订阅者登记在列表中
public void removeObserver(Observer o);//将订阅者从列表中移除
public void notifyObservers(Object arg);//有参通知方法,有新的消息即使通知列表中所有订阅者
public void notifyObservers();//无参通知方法
}

Subject

  观察者所具有的东西就会少一些:

    首先,内部需要有存储主题的对象,这样知道观察者所订阅的报社是哪一家,具有主题对象还有一个重要的原因,把登记、删除、通知观察者的功能全部委托给主题去做。

    其次,还需要有更新自己消息的方法(update())新的消息发送过来,观察者也要及时更新自己内部消息,将旧的消息替换成新的消息。

 public interface Observer{//所有订阅者要实现的接口
/*在接口中,没有主题对象,也是因为不想将主题对象写死在接口中,
在具体类中写入更好*/ public void update(Subject sub, Object args);//接收到新消息,及时更新
}

Observer

现在,我们来以具体的生活例子来介绍如何实现观察者模式(Observer Pattern):

  有一家气象站,气象站本身已经具有WeatherData对象(相当于报社功能,可以获得目前的温度、湿度、气压三种数据)。

  我们需要编写一个应用,该应用有很多种显示模式(从温度、湿度、气压中任选一到三个组合就是一种模式)。

  当WeatherData对象获得最新的测量数据时,我们的应用可以及时更新显示模式中的数据。

根据要求写程序:

  主题接口:

 public interface Subject {//主题接口,所有报社都要实现该接口

     /*没有存储订阅者的列表,是因为我们不想在接口中写死存储方式,
让编程人员自己在实现接口的时候写入想要的存储方式(如:链表,数组,栈,队列等)
这样更合理。*/ public void registerObserver(Observer o);//将订阅者登记在列表中
public void removeObserver(Observer o);//将订阅者从列表中移除
public void notifyObservers(Object arg);//有参通知方法,有新的消息即使通知列表中所有订阅者
public void notifyObservers();//无参通知方法
}

Subject

  主题接口实体类:

 import java.util.ArrayList;

 public class WeatherData implements Subject{//气象站的实现类
private ArrayList observers;//观察者列表
private float temperature;//数据之一:温度
private float humidity;//数据之二:湿度
private float pressure;//数据之三:气压
private boolean status;//数据是否更新的标志 public WeatherData(){//初始化时,为观察者列表赋值
observers = new ArrayList();
} public float getTemperature(){//获取温度的方法
return this.temperature;
} public float getHumidity(){//获取湿度的方法
return this.humidity;
} public float getPressure(){//获取气压的方法
return this.pressure;
} public void registerObserver(Observer o){//将观察者记录在列表中
observers.add(o);
} public void removeObserver(Observer o){//将观察者从列表中删除
int i = observers.indexOf(o);
observers.remove(i);
} public void notifyObservers(Object args){//有参通知观察者方法
if(status){//判断数据是否有更新
for(int i = 0; i < observers.size(); i++){
Observer observer = (Observer) observers.get(i);
observer.update(this, args);
}
status = false;//消息发送成功后,将更新标志位重置
}
} public void notifyObservers(){//无参通知观察者方法
notifyObservers(null);
} public void setChange(){//数据是否更新的标志
status = true;
} public void setMeasurements(float temperature, float humidity, float pressure){//数据更新方法
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
} public void measurementsChanged(){//数据改变后调用该方法
setChange();
notifyObservers();
} }

WeatherData

  观察者接口:

 public interface Observer{//所有订阅者要实现的接口
/*在接口中,没有主题对象,也是因为不想将主题对象写死在接口中,
在具体类中写入更好*/ public void update(Subject sub, Object args);//接收到新消息,及时更新
}

Observer

  显示更新数据的接口:

 public interface DisplayElement{//显示更新数据的接口
public void display();
}

DisplayElement

  观察者接口实体类:

 public class CurrentConditionsDisplay implements Observer, DisplayElement{//显示当前温度、湿度的类
private WeatherData weatherData;//定义订阅的主题对象
private float temperature;//温度数据
private float humidity;//湿度数据 public CurrentConditionsDisplay(WeatherData weatherData){
this.weatherData = weatherData;
weatherData.registerObserver(this);//将该观察者对象登记在主题的观察者列表中
} public void update(Subject sub, Object args){//数据更新方法
if(sub instanceof WeatherData){
WeatherData weatherData = (WeatherData) sub;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
} public void display(){//显示数据的方法
System.out.println("Current conditions:" + temperature + "F degrees and " + humidity + "%humidity");
}
}

CurrentConditionsDisplay

  测试类:

 public class WeatherStation{
public static void main(String[] agrs){
WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); weatherData.setMeasurements(80, 65, 30.4f);//更新数据
weatherData.setMeasurements(82, 70, 29.2f);//更新数据
weatherData.setMeasurements(79, 90, 29.2f);//更新数据
}
}

WeatherStation

编译运行结果:

上面代码已经很完善了,而且不知道你有没有发现,其实每次WeatherData更新数据都是把所有数据都更新,但是我们的CurrentConditionsDispaly只获取温度和湿度两个数据,并且从来不获取多余的气压数据。这就是数据推送(Push)和数据抽取(Pull)的区别。

Push:不管你有没有订阅该数据,主题都会将该数据发送给订阅者,再由订阅者决定数据的取舍,没用的数据就不会记录在自己的数据中。

Pull:订阅者想要什么数据由订阅者说了算,主题只需提供获取数据的方法(get...())就好,而上面我们的气象站就是使用了数据抽取方式。

思想提炼:

  1.多用组合,少用继承

  2.为交互对象之间的松耦合设计而努力

  

2.Observer Pattern(观察者模式)的更多相关文章

  1. 设计模式(二)The Observer Pattern 观察者模式

    问题引入 生成一个公告板显示当时的天气状况,当天气状况发生改变的时候公告板能够实时的更新. 模式定义 定义对象之间的一对多的依赖.当一个对象改变状态时,它的全部依赖者都会自己主动收到通知并自己主动更新 ...

  2. Observer pattern 观察者模式

    一.认识观察者模式 我们看看报纸和杂志的订阅是怎么回事: 1.报社的业务就是出版报纸. 2.向某家报社订阅报纸,只要他们有新的报纸出版,就会给你送来,只要你是他们的订户,你就会一直收到报纸. 3.当你 ...

  3. 设计模式之 Observer Pattern 观察者模式

    1.Subject通过一个容器保存零到多个Observer. 2.Subject通过Add,Delete方法调整Observer. 3.Subject的notifyObservers方法实际是逐个调用 ...

  4. Design Pattern: Observer Pattern

    1. Brief 一直对Observer Pattern和Pub/Sub Pattern有所混淆,下面打算通过这两篇Blog来梳理这两种模式.若有纰漏请大家指正. 2. Use Case 首先我们来面 ...

  5. 设计模式复习小结一(Strategy Pattern/Observer Pattern/Decorator Patter/Factory Pattern)

    目录: 前言 1. Stratrgy Pattern 2. Observer Pattern 3. Decorator Pattern 4. Factory Pattern 4.1 FactoryPa ...

  6. 深入浅出设计模式——观察者模式(Observer Pattern)

    模式动机 建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应.在此,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而 ...

  7. 设计模式 - 观察者模式(Observer Pattern) 详细说明

    观察者模式(Observer Pattern) 详细说明 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权全部 ...

  8. 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)

    原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...

  9. 设计模式 - 观察者模式(Observer Pattern) 详细解释

    观察者模式(Observer Pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权全部 ...

  10. C#设计模式之十七观察者模式(Observer Pattern)【行为型】

    一.引言   今天是2017年11月份的最后一天,也就是2017年11月30日,利用今天再写一个模式,争取下个月(也就是12月份)把所有的模式写完,2018年,新的一年写一些新的东西.今天我们开始讲& ...

随机推荐

  1. css伪元素:before和:after用法详解

    css的伪元素,之所以被称为伪元素,是因为他们不是真正的页面元素,html没有对应的元素,但是其所有用法和表现行为与真正的页面元素一样,可以对其使用诸如页面元素一样的css样式,表面上看上去貌似是页面 ...

  2. 开机或联网时自启动gunicorn

    网站部署完后,如果每次使用gunicorn启动网站会很麻烦,因此必须使gunicorn自启动. 环境 ubuntu 16. 参考: http://www.yangfan.cc/zhanzhang/14 ...

  3. mybatis四大接口之 ParameterHandler

    1.  继承结构 只有一个默认的实现类 2. ParameterHandler 获取参数对象: 设置参数对象: public interface ParameterHandler { Object g ...

  4. linux服务器ssh免密码登录

    假设有三台服务器的ip分别是10.9.1.101.10.9.1.102.10.9.1.103 修改hosts文件 分别修改三台服务器的hosts的文件(vi /etc/hosts), 在hosts文件 ...

  5. ssh免密码登录Permission denied (publickey,gssapi-keyex,gssapi-with-mic) 的解决方案!

    当出现Permission denied (publickey,gssapi-keyex,gssapi-with-mic) 警告的时候,恭喜你,你已经离成功很近了. 远程主机这里设为slave2,用户 ...

  6. 关于并发用户数的思考-通过PV量换算并发

    首先介绍一下pv量:PV(访问量):即Page View, 即页面浏览量或点击量,用户每次刷新即被计算一次.UV(独立访客):即Unique Visitor,访问您网站的一台电脑客户端为一个访客.00 ...

  7. 课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 2、编程作业常见问题与答案(Programming Assignment FAQ)

    Please note that when you are working on the programming exercise you will find comments that say &q ...

  8. [个人项目] 使用 Vuejs 完成的音乐播放器

    Foreword 虽然音乐播放这类的项目的静态展示居多,业务逻辑并不复杂,但是对于我这种后端出身的前端萌新来说,能使用vuejs完成大部分功能, 也会有许多收获. api:我使用的是一个开源的 nod ...

  9. JavaScript -- Form

    -----048-Form.html----- <!DOCTYPE html> <html> <head> <meta http-equiv="co ...

  10. Python做int()强制类型转换的时候,小数是如何取舍的?

    白月黑羽今天给大家分享一个冷知识:) int()强制类型转换小数是如何取舍的? 使用 int() 将小数转换为整数,小数取整会采用比较暴力的截断方式,即小数点后面的会被强制舍去,向下取整. 例如:5. ...