观察者模式

观察者模式也叫作发布-订阅模式,也就是事件监听机制。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己

观察者模式的结构

一个软件系统常常要求在某一个对象状态发生变化时,某些其他的对象作出相应的改变。能做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合度的设计方案。减少对象之间的耦合有利于系统的复用,但是同时需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作。观察者模式是满足这一要求的各种设计方案中最重要的一种。

观察者模式所涉及的角色有:

1、抽象主题角色

抽象主题角色把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。

2、具体主题角色

将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过的观察者发出通知。

3、抽象观察者角色

为所有的具体观察者提供一个接口,在得到主题通知时更新自己

4、具体观察者角色

存储与主题的状态相关的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态协调

观察者模式实例

抽象主题角色,有增加观察者、删除观察者、通知观察者的功能:

public abstract class Subject
{
/** 用来保存注册的观察者对象 */
private List<Observer> list = new ArrayList<Observer>(); /** 注册观察者对象 */
public void attch(Observer observer)
{
list.add(observer);
System.out.println("Attached an observer");
} /** 删除观察者对象 */
public void detach(Observer observer)
{
list.remove(observer);
System.out.println("Detached an observer");
} /** 通知所有注册的观察者对象 */
public void notifyObservers(String newState)
{
for (int i = 0; i < list.size(); i++)
{
list.get(i).update(newState);
}
}
}

具体主题角色,这个change方法放在子类中是因为可能不同的主题在改变观察者状态的时候会做一些不同的操作,因此就不统一放在父类Subject里面了:

public class ConcreteSubject extends Subject
{
private String state; public String getState()
{
return state;
} public void change(String newState)
{
state = newState;
System.out.println("主题状态为:" + state); // 状态发生改变时,通知各个观察者
this.notifyObservers(state);
}
}

观察者接口:

public interface Observer
{
void update(String state);
}

具体观察者实现了观察者接口:

public class ConcreteObserver implements Observer
{
/** 观察者的状态 */
private String observerState; public void update(String state)
{
/** 更新观察者的状态 */
observerState = state;
System.out.println("状态为:" + observerState);
}
}

客户端调用代码,一旦主题调用了change方法改变观察者的状态,那么观察者Observer里面的observerState全都改变了:

public static void main(String[] args)
{
/** 创建主题角色 */
ConcreteSubject subject = new ConcreteSubject(); /** 创建观察者对象 */
Observer observer = new ConcreteObserver(); /** 将观察者注册到主题对象上 */
subject.attch(observer); /** 改变主题对象的状态 */
subject.change("new state");
}

运行结果为:

Attached an observer
主题状态为:new state
状态为:new state

这里只添加了一个观察者,有兴趣的可以试试看多添加几个观察者,效果都是一样的,主题角色改变状态,观察者状态全变。

观察者模式的两种模型

1、推模型

主题对象向观察者推送主题的详细信息,不管观察者是否需要。推送的信息通常是主题对象的全部或部分数据,上面的例子就是典型的推模型

2、拉模型

主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中去获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样观察者在需要获取数据的时候,就可以通过这个引用来获取了。

两种模型的比较

1、推模型是假设主题对象知道观察者需要的数据,拉模型是假设主题对象不知道观察者需要什么数据,干脆把自身传递过去,让观察者自己按需要取值

2、推模型可能会使得观察者对象难以复用,因为观察者的update()方法是按需要定义的参数,可能无法兼顾到没有考虑到的使用情况,这意味着出现新的情况时,可能要提供新的update()方法

观察者模式在Java中的应用及解读

JDK是有直接支持观察者模式的,就是java.util.Observer这个接口:

public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}

这就是观察者的接口,定义的观察者只需要实现这个接口就可以了。update()方法,被观察者对象的状态发生变化时,被观察者的notifyObservers()方法就会调用这个方法:

public class Observable {
private boolean changed = false;
private Vector obs; /** Construct an Observable with zero Observers. */ public Observable() {
obs = new Vector();
} /**
* Adds an observer to the set of observers for this object, provided
* that it is not the same as some observer already in the set.
* The order in which notifications will be delivered to multiple
* observers is not specified. See the class comment.
*
* @param o an observer to be added.
* @throws NullPointerException if the parameter o is null.
*/
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
...
}

这是被观察者的父类,也就是主题对象。这是一个线程安全的类,是基于Vector实现的。主题对象中有这些方法对观察者进行操作:

方  法 作  用
addObserver(Observer o) 如果观察者与集合中已有的观察者不同,则向对象的观察者集合中添加此观察者
clearChanged()、hasChanged()、setChanged() 这三个方法算是一对,用来标记此观察者对象(主题对象)是否被改变的状态的
countObservers() 返回观察者对象的数目
deleteObserver(Observer o) 从对象的观察者集合中删除某个观察者
deleteObservers() 清除观察者列表
notifyObservers()、notifyObservers(Object arg) 如果本对象有变化则通知所有等级的观察者,调用update()方法

利用JDK支持的主题/观察者的例子

创建一个观察者:

public class Watched extends Observable
{
private String data = ""; public String getData()
{
return data;
} public void setData(String data)
{
if (!this.data.equals(data))
{
this.data = data;
setChanged();
}
notifyObservers();
}
}

创建一个主题:

public class Watcher implements Observer
{
String data; public Watcher(Observable o)
{
o.addObserver(this);
} public String getData()
{
return data;
} public void update(Observable o, Object arg)
{
this.data = ((Watched)o).getData();
System.out.println("状态发生改变:" + ((Watched)o).getData());
}
}

写一个main函数调用一下:

public static void main(String[] args)
{
/** 创建被观察者对象 */
Watched watched = new Watched(); /** 创建观察者对象,并将被观察者对象登记 */
Watcher watcher = new Watcher(watched); /** 给被观察者状态赋值 */
watched.setData("start");
watched.setData("run");
watched.setData("stop");
}

运行结果为:

状态发生改变:start
状态发生改变:run
状态发生改变:stop

看到主题对象改变的时候,观察者对象的状态也随之改变

观察者模式的优点以及实际应用

引入设计模式最主要的作用我认为就是两点:

1、去重复代码,使得代码更清晰、更易读、更易扩展

2、解耦,使得代码可维护性更好,修改代码的时候可以尽量少改地方

使用观察者模式可以很好地做到这两点。增加观察者,直接new出观察者并注册到主题对象之后就完事了,删除观察者,主题对象调用方法删除一下就好了,其余都不用管。主题对象状态改变,内部会自动帮我们通知每一个观察者,是不是很方便呢?

观察者模式主要应用场景有:

1、对一个对象状态的更新需要其他对象同步更新

2、对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节,如消息推送

Java设计模式10:观察者模式的更多相关文章

  1. 理解java设计模式之观察者模式

    在生活实际中,我们经常会遇到关注一个事物数据变化的情况,例如生活中的温度记录仪,当温度变化时,我们观察它温度变化的曲线,温度记录日志等.对于这一类问题,很接近java设计模式里面的“观察者模式”,它适 ...

  2. java设计模式之观察者模式以及在java中作用

    观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式.模型-视图(Model/View)模式.源-监听器(Source/Listener)模式或从属者(Dependen ...

  3. java设计模式02观察者模式

    观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 这里主要讲一下学习内置观察者的记录,在JA ...

  4. java设计模式之观察者模式

    观察者模式 观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式.模型-视图(View)模式.源-收听者(Listener)模式或从属者模式)是软件设计模式的一种.在此种模 ...

  5. JAVA设计模式 之 观察者模式

    简介: 观察者模式是JDK中最多的设计模式之一,非常有用,观察者模式介绍了一对多的依赖关系及松耦合,有了观察者,你将会消息灵通. 认识观察者模式,看一个报纸.杂志订阅是怎么回事: (1). 报社的业务 ...

  6. java设计模式之观察者模式(9)

    Java观察者模式的浅析 简单地说,观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监察一个主题对象.这样一个主题对象在状态上的变化能够通知所有的依赖于此对象的那些观察者对象,使这些观察者 ...

  7. 折腾Java设计模式之观察者模式

    观察者模式 Define a one-to-many dependency between objects where a state change in one object results in ...

  8. java设计模式之-观察者模式(发布-订阅模式)

    1.观察者模式定义  观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象. 这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己. 2.观察者模式结构 ...

  9. Java设计模式应用——观察者模式

    告警结果产生后,可能需要发送短信,邮件,故障管理系统.这些转发操作不应当影响告警生成入库,并且类似事件可能根据不同场景,客户习惯不同,此时,使用观察者模式则可以很好的适应上述场景. 观察者模式应当包括 ...

随机推荐

  1. android基于GPS实现定位操作

    一.定位的三种方式 1.wifi定位,ip地址定位,通过ip地址进行查询实际地址: 2.基站定位,信号塔,基站:手机通讯服务的设备 ,信号的格数决定了手机距离基站远近,精确度:几十米到几公里,精确度来 ...

  2. Spring 4 官方文档学习(十三)集成其他web框架

    重点是通用配置,非常建议看一下!有助于理解Spring的ApplicationContext与Servlet Container的关系! 1.介绍 Spring Web Flow SWF目标是成为we ...

  3. OleDb 内存泄露问题

    近期在定位问题时发现使用OleDb打开很大的Excel文件后,即使什么都不操作Colse掉,内存释放了部分,但是并未回到打开前的水平.在Excel 150M,解压缩后900M的场景下,打开后直接Clo ...

  4. 日志——JSON的相关方法

    http://www.cnblogs.com/henryxu/archive/2013/03/10/2952738.html JSON  jar包: commons-lang.jar commons- ...

  5. 18.safari 安装后flash还是提示安装 flash,视频不能播放

    第一步: safari---->偏好设置(首先安装最新Mac adobe flash) 第二步: 第三步:点击进入 第四步:再次打开safar,大功告成!

  6. block的复习

    main.m // //  main.m //  8A10.Block的复习 // //  Created by huan on 16/2/8. //  Copyright © 2016年 huanx ...

  7. Python 学习---------Day2

    第四章 介绍Python对象类型为什么使用内置类型 内置对象使程序更容易编写 内置对象是拓展的组件 内置对象往往比定制的数据结构更有效率 内置对象是语言标准的一部分Python的核心数据类型 数字 字 ...

  8. (转)CentOs上配置samba服务

    前 言 在我们使用 Windows 作为客户机的时候,通常有文件.打印共享的需求.作为Windows 网络功能之一,通常可以在 Windows 客户机之间通过 Windows Network 固有的功 ...

  9. myeclipse使用maven插件进行maven install时报错check $m2_home environment variable and mvn script match

    check $m2_home environment variable and mvn script match 分类: maven2015-09-01 18:06 842人阅读 评论(0) 收藏 举 ...

  10. [Leetcode][JAVA] Insert Interval

    Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessa ...