JAVA设计模式之观察者模式
来源:互联网 发布:U递索引超出了数组界限 编辑:程序博客网 时间:2024/05/22 05:24
观察者模式
1.什么是观察者模式?
《Head Frist设计模式》中定义是:在对象之间定义一对多的依赖关系,当一个对象改变状态,依赖它的对象都会收到通知并自动更新。
观察者和被观察者之间用松耦合的方式结合,被观察者不知道观察者的细节,只知道观察者实现了统一的观察者接口Observer,在JDK中已经默认提供。
被观察者可以称为主题(Subject),默认都继承了统一的被观察者超类Observable。
有多个观察者时,通知是无序的,不能依赖特定的通知顺序,否则会有意外的错误。
观察者模式传递数据有两种:推模式和拉模式。
2.角色
观察者模式的角色组成(图片来源于网络):
(1)、被观察者接口(Subject):抽象被观察者的基本行为,所有被观察者必须要实现此类(注意:JDK自带实现是一个超类Observable,不是一个接口)。
(2)、观察者接口(Observer):抽象观察者的基本行为,是所有观察者的共同接口(注意:JDK自带实现接口也是Observer类,只有一个方法:update(Observable o, Object arg))。
(3)、具体被观察者(ConcreteSubject):具体的一个被观察者,可以拥有多个观察者(如果使用JDK自带的,就只需要继承Observable类)。
(4)、具体观察者(ConcreteObserver):具体的观察者,必须实现Observer接口(Observer接口可以自己实现,也可以使用JDK自带的)。
3.优点
(1)、在观察者与被观察者之间建立了抽象的耦合,使两者之间采用松耦合的方式结合。被观察者不知道观察者的具体细节,只知道一个注册观察者的列表和观察者们统一实现的共同接口。
(2)、观察者模式支持广播通讯。被观察者会向所有注册过的观察者发送通知。
4.缺点
(1)、观察者数目太多的时候,被观察者通知观察者的时间会很长。
(2)、如果观察者和被观察者之间存在循环依赖,可能导致系统奔溃。
(3)、观察者知道被观察者发生了变化,但是不知道发生了怎样的变化。
(4)、java.util.Observable的缺点:首先Observable是一个类,不是一个接口,在面向接口编程的原则中不是一件好事儿,继承Observable类就不能继承其他类(java单一继承),因此限制了Observable类的复用潜力。
5.使用场景
(1)、当一个对象状态的变化需要通知另外几个对象时。
(2)、发布-订阅模式、广播模式的功能。
6.实例代码
(1)首先自己实现一个观察者模式。
此功能为“天气播报功能”。WeatherDate是一个被观察者,主要负责获取天气数据。数据获取过后分别通知ShiduDisplay(湿度显示板)、WenduDisplay(温度显示板)和YaliDisplay(压力显示板)三个显示板进行显示。
(a)、被观察者接口
/**
* 被观察者接口
* @date 2017年8月24日 下午4:33:26
*/
public interface Subject {
/*
* 添加观察者
*/
public void addObserver(Observerobserver);
/*
* 移除观察者
*/
public void removeObserver(Observerobserver);
/*
* 通知观察者
*/
public void notifyObserver();
}
(b)被观察者-天气数据获取类
/**
* 天气信息获取类
* @date 2017年8月29日 上午11:32:49
*/
public class WeatherDateimplements Subject{
private Float wendu;//温度
private Float shidu;//湿度
private Float yali;//压力
/*
* 已注册的观察者集合
*/
private List<Observer>observerList;
public Float getWendu() {
return this.wendu;
}
public Float getShidu() {
return this.shidu;
}
public Float getYali() {
return this.yali;
}
public WeatherDate(){
observerList=new ArrayList<Observer>();
}
@Override
public void addObserver(Observerobserver) {
if(observerList!=null)
observerList.add(observer);
}
@Override
public void removeObserver(Observerobserver) {
if(observer!=null){
int index=observerList.indexOf(observer);
if(index>=0)
observerList.remove(index);
}
}
@Override
public void notifyObserver() {
if(observerList!=null &&observerList.size()>0){
for(Observer ob:observerList)
ob.update(this,null);
}
}
/**
* 设置天气数据
* @param wendu
* @param shidu
* @param yali
* @return void 返回类型
* @throws
* @auter leitao
* @date 2017年8月29日
*/
public void setWeatherData(Floatwendu,Floatshidu,Float yali){
this.wendu=wendu;
this.shidu=shidu;
this.yali=yali;
notifyObserver();
}
}
(c)观察者接口
/**
* 观察者接口
* @date 2017年8月24日 下午4:35:08
*/
public interface Observer {
/**
* 观察者动作
* @param subject 被观察者对象
* @param arg 参数
* @auter leitao
* @date 2017年8月29日
*/
public void update(Subjectsubject,Objectarg);
}
(d)湿度显示板
public class ShiduDisplayimplements Observer, Display {
private Float shidu;// 湿度
public ShiduDisplay(SubjectweatherDate) {
// 注册成为观察者
if (weatherDate !=null)
weatherDate.addObserver(this);
}
@Override
public void display() {
System.out.println(" shiduDisplay getData:" +this.shidu);
}
@Override
public void update(Subjectsubject, Objectarg) {
if (subject instanceof WeatherDate) {
WeatherDate wd = (WeatherDate) subject;
this.shidu =wd.getShidu();
display();
}
}
}
(e)温度显示板
public class WenduDisplayimplements Observer, Display {
private Float wendu;// 温度
public WenduDisplay(SubjectweatherDate) {
// 注册成为观察者
if (weatherDate !=null)
weatherDate.addObserver(this);
}
@Override
public void display() {
System.out.println(" wenduDisplay getData:" +this.wendu);
}
@Override
public void update(Subjectsubject, Objectarg) {
if (subject instanceof WeatherDate) {
WeatherDate wd = (WeatherDate) subject;
this.wendu =wd.getWendu();
}
display();
}
}
(f)压力显示板
public class YaliDisplayimplements Observer, Display {
private Float yali;// 压力
public YaliDisplay(SubjectweatherDate) {
// 注册成为观察者
if (weatherDate !=null)
weatherDate.addObserver(this);
}
@Override
public void display() {
System.out.println(" yaliDisplay getData:" +this.yali);
}
@Override
public void update(Subjectsubject, Objectarg) {
if (subject instanceof WeatherDate) {
WeatherDate wd = (WeatherDate) subject;
this.yali =wd.getYali();
display();
}
}
}
(g)显示面板统一接口
/**
*显示面板操作统一接口
* @ClassName: Display
* @author Administrator
* @date 2017年8月24日 下午4:35:55
*/
public interface Display {
public void display();
}
(h)运行
public static void main(String[]args) {
WeatherDate wd=new WeatherDate();
WenduDisplay wdd=new WenduDisplay(wd);
ShiduDisplay sdd=new ShiduDisplay(wd);
YaliDisplay yld=new YaliDisplay(wd);
//wd.removeObserver(yld);
wd.setWeatherData(27.6f, 33f, 105f);
}
(i)运行结果
wenduDisplay getData:27.6
shiduDisplay getData:33.0
yaliDisplay getData:105.0
(2)通过JDK自带实现的观察者模式改造“天气播报功能”。
(a)天气获取类
import java.util.Observable;
import ...
public class WeatherDateextends Observable{
private Float wendu;
private Float shidu;
private Float yali;
public Float getWendu() {
return wendu;
}
public Float getShidu() {
return shidu;
}
public Float getYali() {
return yali;
}
/**
* 更改数据
* @param wendu
* @param shidu
* @param yali
* @auter leitao
* @date 2017年8月28日
*/
public void setWeatherData(Floatwendu,Floatshidu,Float yali){
this.wendu=wendu;
this.shidu=shidu;
this.yali=yali;
setChanged();//参考如下“★”
notifyObservers();
}
}
(b)温度显示板
import java.util.Observable;
import java.util.Observer;
/**
* 温度显示类
* @date 2017年8月28日 下午3:01:04
*/
public class WenduDisplayimplements Observer{
private Float wendu;
/**
* 注册成为WeatherDate的观察者
* @param weatherDate
*/
public WenduDisplay(WeatherDateweatherDate) {
if(weatherDate!=null)
weatherDate.addObserver(this);
}
/**
* 数据显示
* @auter leitao
* @date 2017年8月28日
*/
public void display() {
System.out.println(" wenduDisplay getData:"+this.wendu);
}
@Override
public void update(Observablesubject, Objectarg) {
if(subject instanceof WeatherDate){
WeatherDate wd=(WeatherDate)subject;
this.wendu=wd.getWendu();
}
display();
}
}
(c)湿度显示板
/**
* 湿度显示类
* @date 2017年8月28日 下午2:58:16
*/
public class ShiduDisplayimplements Observer{
private Float shidu;
/**
* 注册成为WeatherDate的观察者
* @param weatherDate
*/
public ShiduDisplay(WeatherDateweatherDate) {
if (weatherDate !=null)
weatherDate.addObserver(this);
}
@Override
public void update(Observableo, Objectarg) {
if(o instanceof WeatherDate){
WeatherDate wd=(WeatherDate) o;
//此处采用向被观察者 拉 数据的方式获取数据
this.shidu=wd.getShidu();
display();
}
}
public void display() {
System.out.println(" shiduDisplay getData:"+this.shidu);
}
}
(d)压力显示板
/**
* 压力显示类
* @date 2017年8月28日 下午3:02:22
*/
public class YaliDisplayimplements Observer {
private Float yali;
/**
* 注册成为WeatherDate的观察者
* @param weatherDate
*/
public YaliDisplay(WeatherDateweatherDate) {
if (weatherDate !=null)
weatherDate.addObserver(this);
}
public void display() {
System.out.println(" yaliDisplay getData:"+this.yali);
}
@Override
public void update(Observablesubject, Objectarg) {
if(subject instanceof WeatherDate){
WeatherDate wd=(WeatherDate) subject;
this.yali=wd.getYali();
display();
}
}
}
(e)运行
public static void main(String[]args) {
WeatherDate wd=new WeatherDate();
WenduDisplay wdd=new WenduDisplay(wd);
ShiduDisplay sdd=new ShiduDisplay(wd);
YaliDisplay yld=new YaliDisplay(wd);
wd.deleteObserver(yld);
//wd.deleteObservers();
//wd.countObservers();
//wd.hasChanged();
wd.setWeatherData(27.6f, 33f, 105f);
}
(f)运行结果
shiduDisplay getData:33.0
wenduDisplay getData:27.6
(3)JDK之Observable类补充
Observable类主要方法如下:
addObserver(Observer o);//注册观察者
deleteObserver(Observer o);//删除观察者
notifyObservers();//通知所有观察者
notifyObservers(Object arg);//通知所有观察者,并向观察者传参数
deleteObservers();//删除所有观察者
setChanged();//设置通知状态
clearChanged();//刷新通知状态
hasChanged();//获取通知状态
countObservers();//获取当前注册的观察者数量
Observable类主要变量:
private boolean changed =false;//通知状态,初始值为false
private Vector obs;//观察者集合
此处着重讲一下changed参数和setChanged()方法。changed参数默认是false,主要使用与notifyObservers(Object arg)方法中,用于控制是否通知观察者们。
代码如下:
public void notifyObservers(Objectarg) {
Object[] arrLocal;
synchronized (this) {
/*
*如果通知状态为false则返回,如果为true则挨个调用观察者们的*update方法
*/
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i =arrLocal.length-1;i>=0;i--)
((Observer)arrLocal[i]).update(this,arg);
}
★因此,在被观察者中调用notifyObservers(Object arg)和notifyObservers()方法之前,必须要先调用setChanged()方法设置通知状态,否者notify方法无效。
【乐山程序员联盟,欢迎大家加群相互交流学习5 7 1 8 1 4 7 4 3】
- java设计模式之“观察者设计模式”
- Java设计模式之观察者设计模式
- 《java设计模式》之观察者设计模式
- Java设计模式之观察者
- Java设计模式之观察者
- Java设计模式之Observer(观察者)模式
- Java设计模式之Observer 观察者模式
- Java设计模式之Observer-观察者模式
- java 设计模式之二-观察者模式
- Java设计模式之观察者模式
- java设计模式之观察者模式
- java设计模式之观察者模式Observer
- java设计模式之观察者模式
- Java设计模式之观察者模式
- JAVA设计模式之观察者模式2
- java与设计模式之观察者模式
- Java--设计模式之观察者模式
- java设计模式之观察者模式
- 第27节:通过py2exe将自动化脚本打包成一个exe
- 侧滑界面/侧拉菜单
- Mysql VS2015调用
- Spring学习之路-装配Bean
- Vue.js使用Stylus
- JAVA设计模式之观察者模式
- VI在各类型活动展示中的要点
- Hadoop中的Hbase
- 选择子序列(51nod-1153)
- 自然语言处理(NLP)常用开源工具总结----不定期更新
- java中instanceof用法
- hadoop-2.7.3 在windows环境下安装(无需Cygwin)
- vetur插件提示 [vue-language-server] Elements in iteration expect to have 'v-bind:key' directives错误的解决办法
- qt QTableWidget&&QTableView 导出数据到excel