一:什么是观察者模式:

官方定义:定义对象间一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

举个例子,很多人都会订阅天气预报,当气象台获得明天的天气情况(目标对象)时,就会短信通知订阅了天气预报的人(观察者),然后订阅者就会根据明天天气情况做出相应的处理(呆在家?出去踏青?出去购物...)

二:观察者模式的两个角色:

第一个角色:目标对象(subject),被观察者关注的对象,它的改变引起观察者的改变,例如上面提到的天气情况。

第二个角色:观察者(observer),一个或者多个,关注着目标对象的状态,例如上例的订阅了天气预报的人群。

三:观察者模式三种常见的角色场景:

1. 一个目标对象,一个观察者对象,比如只要你一个人订阅了天气预报

2. 一个目标对象,多个观察者对象,比如,你爸爸,你妈妈和你都订阅了天气预报

3. 多个目标对象,一个观察者对象,比如你一个人订阅了天气预报,还订阅了报纸

四:推模型和拉模型(后面的代码会有注释):

推模型:observer在执行update()方法时,获取的是subject传给它的具体参数,目标对象主动向观察者推送目标的详细信息。

拉模型:observer在执行update()方法时,获得的是subject传给它的一个subject对象,observer需要什么参数自己去取。

五:java代码实行观察者模式:

首先提供最基本的观察者模式代码框架:

1. 新建一个Subject父类

import java.util.ArrayList;
import java.util.List; /*
* 目标对象,他知道观察它的观察者,并提供注册(添加)和删除观察者的接口
*/
public class Subject {
//用来保存注册的观察者对对象
private List<Observer> observers = new ArrayList<Observer>(); //将观察者添加多list对象中
public void attch(Observer observer){
observers.add(observer);
} //删除集合中的指定观察者对象
public void delete(Observer observer){
observers.remove(observer);
} //向所有注册了的观察者通知消息
protected void notifyObserver() {
for(Observer observer:observers){
observer.update(this);
}
}
}

2. 新建一个具体Subject实现类

   
/*
* 具体的目标对象,负责把有关状态存入到相应的观察者对象
*/
public class ConcreteSubject extends Subject {
//目标对象的状态
private String subjectState; public String getSubjectState() {
return subjectState;
} public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
this.notifyObserver();
} }

3. 新建一个Observer接口

/*
* 这是一个观察者接口,定义一个更新的接口给那些在目标发生改变时,被通知的对象
*/
public interface Observer { /*
* 更新接口
* subject传入的目标对象,方便获取目标对象的状态
*/
public void update(Subject subject); }

4. 新建一个observer实现类

/*
* 具体的观察者对象,实现更新的方法,使自身状态和目标状态一致
*/
public class ConcreteObserver implements Observer { private String observerState;
@Override
public void update(Subject subject) {
// TODO Auto-generated method stub
observerState = ((ConcreteSubject)subject).getSubjectState();
} }

下面我用一个具体的例子,来实现观察者模式,让你更加清晰了解观察者模式

一个这样的场景,小东的女朋友和老妈都订阅了小东开发的一个天气预报软件,当每天天气不同时,小东的女朋友和老妈收到天气情况通知,都会安排明天的行程。小东的这个软件可逗的女朋友和老妈开心了,原来程序猿还有这作用,下面来看程序如何演示的:

1. 新建一个WeatherSubject父目标对象

import java.util.ArrayList;
import java.util.List; /*
* 目标对象,他知道观察它的观察者,并提供注册(添加)和删除观察者的接口
*/
public class WeatherSubject {
//用来保存订阅天气的人
private List<Observer> observers = new ArrayList<Observer>(); //把订阅天气的人添加到订阅列表中
public void attch(Observer observer){
observers.add(observer);
} //删除集合中的指定的订阅天气的人
public void delete(Observer observer){
observers.remove(observer);
} //通知所有已经订阅了天气的人
protected void notifyObserver() {
for(Observer observer:observers){
observer.update(this);
}
}
}

2. 新建一个WeatherSubject具体实现对象( 观察者需要从目标对象中需要获取的的状态只有天气内容)

/*
* 具体的目标对象,负责把有关状态存入到相应的观察者对象
*/
public class ConcreteWeatherSubject extends WeatherSubject {
//获取天气的内容信息
private String weatherContent; public String getWeatherContent() {
return weatherContent;
} public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
//内容有了,说明天气更新了,通知所有订阅的人
this.notifyObserver();
} }

3. 新建一个Observer接口

/*
* 这是一个观察者接口,定义一个更新的接口给那些在目标发生改变时,被通知的对象
*/
public interface Observer { /*
* 更新接口
* subject传入的目标对象,方便获取目标对象的状态
*/
public void update(WeatherSubject subject); }

4. 新建一个具体的WeatherSubject对象

/*
* 具体的观察者对象,实现更新的方法,使自身状态和目标状态一致
*/
public class ConcreteObserver implements Observer { //观察者的名字,是谁收到了这个讯息,小东女朋友还是他老妈
private String observerName; //天气内容的情况,这个消息从目标处获得
private String weatherContent; //提醒的内容,小东的女朋友提醒约会,而他老妈提醒购物
private String remindThing; public String getObserverName() {
return observerName;
}
public void setObserverName(String observerName) {
this.observerName = observerName;
}
public String getWeatherContent() {
return weatherContent;
}
public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
}
public String getRemindThing() {
return remindThing;
}
public void setRemindThing(String remindThing) {
this.remindThing = remindThing;
} public void update(WeatherSubject subject) {
weatherContent = ((ConcreteWeatherSubject)subject).getWeatherContent();
System.out.println(observerName + "收到了" + weatherContent + ","+remindThing);
} }

5. 测试类

public class Client {
public static void main(String[] args) {
//1.创建目标
ConcreteWeatherSubject weatherSubject = new ConcreteWeatherSubject(); //2.创建观察者
ConcreteObserver observerGirl = new ConcreteObserver();
observerGirl.setObserverName("小东的女朋友");
observerGirl.setRemindThing("是我们的第一次约会,地点华罗利广场,不见不散额"); ConcreteObserver observerMom = new ConcreteObserver();
observerMom.setObserverName("小东的老妈");
observerMom.setRemindThing("是一个购物的好日子,明天去老街血拼");
//3.注册观察者
weatherSubject.attch(observerGirl);
weatherSubject.attch(observerMom); //4.目标发布天气
weatherSubject.setWeatherContent("明天天气晴朗,晴空万里,温度28℃");
}
}

6. 运行结果

各位程序猿屌丝们,原来观察者模式还能来泡妞,你还等什么了,现在对观察者模式有了基本的了解了吧。最后我们来谈谈哪些情况能用到观察者模式:

  • 当一个抽象模型有两个方面,其中一个方面的操作依赖与另一方面的状态变化就可以使用观察者模式。
  • 如果在更改一个状态的时候,需要同事连带改变其他对象,而且不知道有多少个对象需要被连带改变时,可以选用观察者模式。
  • 当一个对象必须通知其它对象,但你又希望这个对象和其它被它通知的对象是松散耦合的,也可以使用观察者模式。

谢谢各位看官的赏脸,我们下次再见!

新手码农浅谈观察者模式(java语言简单实现)的更多相关文章

  1. 20190608_浅谈go&java差异(三)

    20190608_浅谈go&java差异(三) 转载请注明出处https://www.cnblogs.com/funnyzpc/p/10990703.html 第三节内容概览 多线程通讯(线程 ...

  2. 20190312_浅谈go&java差异(一)

    多线程 java java中对于大量的比较耗时的任务多采用多线程对方式对任务进行处理,同时由于进程和线程 本身是通过宿主机OS进行管理的,当在cpu核数较少或线程分配不当 会导致多线程的效果不佳的事常 ...

  3. 浅谈C++/JAVA/C#运行机制和执行效率

    估计有很多同学都对C++/JAVA/C#这三大热门语言的运行机制和执行效率有或多或少的困惑,自己也有,但是经过前期的学习,了解了三者在这两方面的区别,就废话不说了,进入主题吧.         一.运 ...

  4. 浅谈对java中传参问题的理解

    之前用的c/c++比较多,在c/c++中对于传参类型,无外乎就是传值.传引用.传指针这几种.但在java中,由于没有指针类型,其传参的方式也发生了相应的变化.在网上找了找,按我之前的理解,java中传 ...

  5. 浅谈一下Java String

    相信很多同学使用Java String, Java中的String方法,但是对其中的原理可能有些模糊,那么咱们就针对这块内容进行展开,让更多的同学理解和知道. public final class S ...

  6. 浅谈在Java开发中的枚举的作用和用法

    枚举(enum),是指一个经过排序的.被打包成一个单一实体的项列表.一个枚举的实例可以使用枚举项列表中任意单一项的值.枚举在各个语言当中都有着广泛的应用,通常用来表示诸如颜色.方式.类别.状态等等数目 ...

  7. 浅谈PL/SQL语言基础

    在前面的学习中,我们大部分接触的都是SQL语言,但是,在实现复杂操作的时候,SQL语言就无能为力了,这时候就需要引入新的语言,PL/SQL语言就是对SQL语言的扩展,可以实现存储过程,函数等的创建.下 ...

  8. 浅谈:java泛型与dao重用

    在进入今天的主题之前,我们先理解一下什么是泛型: 泛型是java中一种类型,泛型是被参数化的类型. 类型-->class 参数化-->class类型可以是任意参数 泛型存在的意义:泛型可以 ...

  9. 浅谈用java解析xml文档(四)

    继续接上一文,这一阵子因为公司项目加紧,导致最后一个解析xml文档的方式,还没有总结,下面总结使用dom4J解析xml. DOM4J(Document Object Model for Java) 使 ...

随机推荐

  1. JavaScript判断IE版本

    判断IE兼容到IE11 IE浏览器与非IE浏览器的区别是IE浏览器支持ActiveXObject,但是非IE浏览器不支持ActiveXObject.在IE11浏览器还没出现的时候我们判断IE和非IE经 ...

  2. android 中调用接口发送短信

    android中可以通过两种方式发送短信 第一:调用系统短信接口直接发送短信:主要代码如下: //直接调用短信接口发短信 SmsManager smsManager = SmsManager.getD ...

  3. java replace和replaceAll

    replace和replaceAll是JAVA中常用的替换字符的方法 public String replace(char oldChar, char newChar)         在字符串中用n ...

  4. Mui框架一 快捷键+基础知识点

    1.折叠面板--mAccordion 2.数字角标-mBadges <h5>有底色</h5> <span class="mui-badge">灰 ...

  5. continue用法

    之前,一直没搞懂continue的用法,现在知道其中一个了: continue语句用于终止本轮循环,返回循环头部,开始下一轮循环 var i = 0; while (i < 10){ i++; ...

  6. [转载]什么是FCKeditor?功能强大的HTML编辑器!

    天天在用FCKeditor写博客,但一直不清楚FCKeditor到底是什么,今天终于找到了一些相关的资料,大家一起来分享下. FCKeditor文本编辑程序(共享软件)为用户提供在线的文档编辑服务,其 ...

  7. python split()函数

    Python split()函数 函数原型: split([char][, num])默认用空格分割,参数char为分割字符,num为分割次数,即分割成(num+1)个字符串 1.按某一个字符分割. ...

  8. “iTunes无法连接iPad,因为设备超时”解决办法

    注意一般要两个授权才会连接成功,一是在电脑上的iTunes登陆apple账户,账户授权电脑:二是ipad上信任Trust电脑连接ipad,如果没有重启iPad试试. 法1. 更新iTunes,重启电脑 ...

  9. 用java程序调用批处理文件

    用java程序执行批处理文件并打印出控制台信息: public class test { public static void main(String[] args) { try { //执行批处理文 ...

  10. 封装获取dom元素

    <script> //函数: 反复执行的代码块 //全局只有一个对象,防止全局变量污染 var itcast = { getElen : { tag : function(tag){ re ...