Java设计模式10:观察者模式
观察者模式
观察者模式也叫作发布-订阅模式,也就是事件监听机制。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
观察者模式的结构
一个软件系统常常要求在某一个对象状态发生变化时,某些其他的对象作出相应的改变。能做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合度的设计方案。减少对象之间的耦合有利于系统的复用,但是同时需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作。观察者模式是满足这一要求的各种设计方案中最重要的一种。
观察者模式所涉及的角色有:
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、对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节,如消息推送
转载于:https://www.cnblogs.com/xrq730/p/4908686.html
Java设计模式10:观察者模式相关推荐
- Java设计模式之观察者模式(UML类图分析+代码详解)
大家好,我是一名在算法之路上不断前进的小小程序猿!体会算法之美,领悟算法的智慧~ 希望各位博友走过路过可以给我点个免费的赞,你们的支持是我不断前进的动力!! 加油吧!未来可期!! 本文将介绍java设 ...
- java 观察者模式_图解Java设计模式之观察者模式
图解Java设计模式之观察者模式 天气预报项目需求 天气预报设计方案 1 - 普通方案 观察者模式(Observer)原理 观察者模式解决天气预报需求 观察者模式在JDK应用的源码分析 天气预报项目需 ...
- Java设计模式系列--观察者模式(使用)
原文网址:Java设计模式系列--观察者模式(使用)_IT利刃出鞘的博客-CSDN博客 简介 说明 本文用示例介绍观察者模式的用法. 观察者模式的含义 以微信公众号为例.我们关注了某个微信公众号后能收 ...
- java设计模式 观察者模式_理解java设计模式之观察者模式
在生活实际中,我们经常会遇到关注一个事物数据变化的情况,例如生活中的温度记录仪,当温度变化时,我们观察它温度变化的曲线,温度记录日志等.对于这一类问题,很接近java设计模式里面的"观察者模 ...
- Java 设计模式之观察者模式
一.了解观察者模式 1.1 什么是观察者模式 观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象状态改变时,它的所有依赖者都会收到通知并自动更新. 典型的问题比如报社,只要你是他们的订户,他们 ...
- Java设计模式10,建造者模式
目录 一.建造者模式 二.建造者模式的结构 1.抽象建造者(Builder) 2.具体建造者(ConcreteBuilder) 3.指挥者(Director) 4.产品(Product) 三.建造者模 ...
- (设计模式十三)java设计模式之观察者模式
特别说明:本篇博客来自于设计模式菜鸟教程 观察者模式 当对象间存在一对多关系时,则使用观察者模式(Observer Pattern).比如,当一个对象被修改时,则会自动通知它的依赖对象.观察者模式属于 ...
- [java设计模式简记] 观察者模式(Observer-Pattern)
观察者模式(Observer-Pattern) 数据主体拥有需要数据的对象的数据,并且数据改变时需要数据的对象要及时知道 意图: 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖 ...
- Java 设计模式之观察者模式(Observer pattern)
观察者模式在软件编程中用的较多,我不善于表达我就用在网上看到的故事,和生活的例子说下基本思想 故事: 小雪是一个非常漂亮的女孩,漂亮的女孩总是有很多的追求者,而且追求者的队伍在不断的变动,随时有人进入 ...
最新文章
- 很好的FireFox addin
- 游戏的革命从虚拟现实开始
- 东芝移动硬盘拆解图_华为Mate40系列新技术曝光:海思闪存亮相,性能超三星东芝...
- UA MATH ECE636 信息论10 Group Testing简介
- OSI网络体系结构各层协议:
- HDU 1754 I Hate It(线段树)
- php取商,PHP获取百度关键词排名
- RTX5 | 消息队列04 - (实战技巧)串口中断回调函数ISR同步线程
- 音频源代码_使用开放源代码从丢失的格式中恢复音频
- Luogu P1039 侦探推理(模拟+枚举)
- (附源码)计算机毕业设计ssm大众点评管理系统
- 经济应用文写作【7】
- bmd硬盘测试_硬盘测速工具:Blackmagic Disk Speed Test Mac
- python 使用 pyodbc 访问 Sql Server
- 电子邮件营销中的邮件主题设计
- pandas 第二章 pandas基础
- 公务员考试计算机专业类别,专业!公务员专业类别划分
- warning: pointer targets in passing argument 3 of ‘accept’ differ in signedness
- Laravel 5.4设置logout注销账户的重定向路径
- 关机程序源代码——千万不要点运行!!!hahaha
热门文章
- php采集网页,phpQuery采集网页实现代码实例
- linux系统硬盘使用过高,磁盘IO过高时的处理办法
- 物联网行业网络解决方案_2021物联网趋势:有望从物联网传感器网络中受益的5大行业...
- 局域网内计算机可以互访 无法上互联网,我使用路由器后访问互联网正常,但是网上邻居不能互访,怎么办?...
- mysql讀取sql_SQL 2008连接读取mysql数据的方法
- MediaSession框架介绍
- Java高并发编程:线程池
- c++重载运算符_Python 运算符重载
- mysql 左连接 例子_mysql左连接自连接例子
- 三维匹配_机器视觉——双目视觉的基础知识(视差深度、标定、立体匹配)