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. Linux基础命令-cd

    cd 作用:切换路径 切换至家目录 $ cd $ cd~ 在上一个目录和当前目录来回切换 $ cd - 切换至某用户的家目录 # cd ~ # pwd /root # cd ~quail #pwd / ...

  2. webstorm “Unterminated statement”

    使用webstorm的时候,写console.log,或者一些其他语句的时候  偶尔会出现这种提示,不是报错,就是看着别扭,应该是写法规范问题. 解决办法: 在下面空一行就行了

  3. typescript-koa-postgresql 实现一个简单的rest风格服务器 —— typescript 开发环境配置

    最近需要用 nodeJS 写一个后台程序,为了能够获得 IDE 的更多代码提示,决定用 typescript 来编写,随便也学习下 ts,在这记录下实现过程. 1.新建文件夹 typescript-k ...

  4. python面试(3)

    一.语言 推荐一本看过最好的python书籍? 拉开话题好扯淡 谈谈python的装饰器,迭代器,yield? 标准库线程安全的队列是哪一个?不安全的是哪一个?logging是线程安全的吗? pyth ...

  5. python实战问题记录

    开发环境搭建 1.安装aiohttp这个异步的http框架失败 提示使用pip更高版本,但是更新之后,还是无法使用.所以,我们采用anaconda中的aiohttp,即打开anaconda,然后进入E ...

  6. springboot + mybatis +druid

    Druid Spring Boot Starter mybatis-spring-boot-autoconfigure mybatis-spring-boot-samples 新建spring boo ...

  7. Attr的visitNewClass()方法解读

    在visitNewClass()方法中有如下注释: We are seeing an anonymous class instance creation.In this case, the class ...

  8. PHP多进程系列笔记(二)

    上一篇文章讲解了pcntl_fork和pcntl_wait两个函数的使用,本篇继续讲解PHP多进程相关新知识. 僵尸(zombie)进程 这里说下僵尸进程: 僵尸进程是指的父进程已经退出,而该进程de ...

  9. CentOS下SSH远程免密登录服务器

    .5服务器上配置,通过ssh远程免密登录192. 1.安装SSH,此处省略 2.生成公钥和私钥,生成的秘钥默认在/root/.ssh/文件夹里面 [root@localhost ~ ::&&a ...

  10. redis集群报Jedis does not support password protected Redis Cluster configurations异常解决办法

    解决spring-data-redis操作redis集群报“Jedis does not support password protected Redis Cluster configurations ...