Observer 观察者模式
| Markdown版本笔记 | 我的GitHub首页 | 我的博客 | 我的微信 | 我的邮箱 |
|---|---|---|---|---|
| MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
Observer 观察者模式 设计模式
目录
简介
最简单的观察者模式
抽象观察者
抽象主题
具体观察者
具体主题
演示案例
观察者模式详细案例
产品对象
抽象主题 Subject
具体主题 ConcreteSubject
抽象观察者 Observer
具体观察者 ConcreteObserver
演示
利用系统提供的两个类
Observer 源码
Observable 源码
利用系统类演示观察者模式
被观察者
观察者
演示
简介
观察者模式有时又被称为发布-订阅(publish-Subscribe)模式、模型-视图(model-View)模式、源-收听者(Source-listener)模式,或从属者模式。在此种模式中,一个【目标物件】管理所有相依于它的观察者物件,并且在它本身的状态改变时【主动】发出通知。这通常通过调用各观察者所提供的接口来实现。此种模式通常被用来实现事件处理系统。
观察者模式定义了对象间的【一对多】关系,当一个对象的行为、状态发生变化时,所有订阅者能够收到相应的通知。
观察者模式一般有2种,一种【推模式】,一个【拉模式】。推模式即当被订阅者对象发生改变时,会主动将变化的消息【推给】订阅者,而不考虑每个订阅者当时的处理能力;另一种是拉模式,即订阅者持有被观察者的实例,当被订阅者的行为发生改变时,拉模式会主动的根据引用【获取】变化的相关数据。
观察者模式中涉及的角色
- 抽象主题[Subject]:即被观察者ObServable
- 具体主题[ConcreteSubject]:在具体主题内部状态改变时,通知观察者
- 抽象观察者[Observer]:为所有具体观察者定义接口
- 具体观察者[ConcreteObserver]:可以保存指向具体主题对象的引用
使用场景 :当一个系统中【某个】对象的改变需要同时改变其他【多个】对象,且它不知道具体有多少对象有待改变时候 使用。
作用:通知对象状态改变 。
最简单的观察者模式
抽象观察者
interface Watcher {
void update(String str);
}
抽象主题
interface Watched {
void addWatcher(Watcher watcher);
void removeWatcher(Watcher watcher);
void notifyWatchers(String str);
}
具体观察者
class ConcreteWatcher implements Watcher {
@Override
public void update(String str) {
Log.i("bqt", "观察者收到被观察者的消息:" + str);
}
}
具体主题
class ConcreteWatched implements Watched {
private List<Watcher> list = new ArrayList<>();
@Override
public void addWatcher(Watcher watcher) {
if (list.contains(watcher)) {
Log.i("bqt", "失败,被观察者已经注册过此观察者");
} else {
Log.i("bqt", "成功,被观察者成功注册了此观察者");
list.add(watcher);
}
}
@Override
public void removeWatcher(Watcher watcher) {
if (list.contains(watcher)) {
boolean success = list.remove(watcher);
Log.i("bqt", "此观察者解除注册观察者结果:" + (success ? "成功" : "失败"));
} else {
Log.i("bqt", "失败,此观察者并未注册到被观察者");
}
}
@Override
public void notifyWatchers(String str) {
for (Watcher watcher : list) {
watcher.update(str);
}
}
}
演示案例
private Watcher watcher;
private Watched watched;
//...
watcher = new ConcreteWatcher();
watched = new ConcreteWatched();
//...
watched.addWatcher(watcher);
watched.notifyWatchers("救命啊");
watched.removeWatcher(watcher);
观察者模式详细案例
产品对象
interface Watcher {
void update(String str);
}
interface Watched {
void addWatcher(Watcher watcher);
void removeWatcher(Watcher watcher);
void notifyWatchers(String str);
}
class ConcreteWatcher implements Watcher {
@Override
public void update(String str) {
Log.i("bqt", "观察者收到被观察者的消息:" + str);
}
}
class ConcreteWatched implements Watched {
private List<Watcher> list = new ArrayList<>();
@Override
public void addWatcher(Watcher watcher) {
if (list.contains(watcher)) {
Log.i("bqt", "失败,被观察者已经注册过此观察者");
} else {
Log.i("bqt", "成功,被观察者成功注册了此观察者");
list.add(watcher);
}
}
@Override
public void removeWatcher(Watcher watcher) {
if (list.contains(watcher)) {
boolean success = list.remove(watcher);
Log.i("bqt", "此观察者解除注册观察者结果:" + (success ? "成功" : "失败"));
} else {
Log.i("bqt", "失败,此观察者并未注册到被观察者");
}
}
@Override
public void notifyWatchers(String str) {
for (Watcher watcher : list) {
watcher.update(str);
}
}
}
private Watcher watcher;
private Watched watched;
//...
watcher = new ConcreteWatcher();
watched = new ConcreteWatched();
//...
watched.addWatcher(watcher);
watched.notifyWatchers("救命啊");
watched.removeWatcher(watcher);
产品对象
发布者要发布什么给订阅者?订阅者要订阅什么?这中间需要定义一个产品对象:
class Product {
public boolean changed = false;
public String message = "";
public int num = -1;
}
抽象主题 Subject
也叫抽象被观察者Observable。抽象主题把所有对观察者对象的引用保存在一个集合里,每个主题都可以有任意数量的观察者。抽象主题可以增加和删除观察者对象
interface Subject {
public void attach(Observer observer); //注册观察者对象
public void detach(Observer observer); //移除/取消注册观察者对象
/**---------上面两个是最基本的方法,下面的方法都不是必须的--------*/
public void nodifyObservers(); //通知所有注册的观察者对象
public void setProduct(Product product); //把通知的内容封装到一个对象中
public Product getProduct(); //获取产品对象
}
具体主题 ConcreteSubject
class ConcreteSubject implements Subject {
private List<Observer> list = new ArrayList<Observer>(); //用来保存注册的观察者对象
private Product product;
@Override
public void attach(Observer observer) {
list.add(observer);
}
@Override
public void detach(Observer observer) {
list.remove(observer);
}
@Override
public void nodifyObservers() {
if (product != null && product.changed) {
System.out.println("具体主题状态发生改变,于是通知观察者:" + product.message + "-" + product.num);
for (Observer observer : list) {
observer.update(product);
}
}
}
@Override
public void setProduct(Product product) {
this.product = product;
}
@Override
public Product getProduct() {
return product;
}
}
抽象观察者 Observer
为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。
interface Observer {
public void update(Product product);
}
具体观察者 ConcreteObserver
实现抽象观察者所要求的更新接口。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用
class ConcreteObserver implements Observer {
public String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(Product product) {
if (product == null) return;
System.out.println("具体观察者【" + name + "】收到消息:" + product.message + "-" + product.num);
}
}
演示
public class Test {
public static void main(String[] args) throws InterruptedException {
Subject subject = new ConcreteSubject();//主题对象
Observer observer1 = new ConcreteObserver("包青天");//观察者对象
Observer observer2 = new ConcreteObserver("白乾涛");
subject.attach(observer1);//将观察者对象注册到主题对象上
subject.attach(observer2);
Product product = new Product(); //主题发布的产品
subject.setProduct(product);
//当主题发布的产品对象的状态改变时,主题通知观察者
product.changed = true;
product.message = "下载进度";
product.num = 15;
subject.nodifyObservers();
//当观察者对象不再需要监控此主题对象时,将观察者对象取消注册到主题对象上
subject.detach(observer1);
}
}
利用系统提供的两个类
Observer 源码
package java.util;
public interface Observer {
void update(Observable o, Object arg);
}
Observable 源码
package java.util;
public class Observable {
private boolean changed = false;//标志被观察者是否改变
private Vector obs;//保存注册的观察者对象
public Observable() {
obs = new Vector();
}
public synchronized void addObserver(Observer o) {
if (o == null) throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed) return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
利用系统类演示观察者模式
被观察者
package java.util;
public interface Observer {
void update(Observable o, Object arg);
}
package java.util;
public class Observable {
private boolean changed = false;//标志被观察者是否改变
private Vector obs;//保存注册的观察者对象
public Observable() {
obs = new Vector();
}
public synchronized void addObserver(Observer o) {
if (o == null) throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed) return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
继承自Observable
class HanFeiZi extends Observable {
public void haveBreakfast() {
System.out.println("韩非子大吼一声:开饭!");
setChanged();
notifyObservers("韩非子开始吃饭了");
}
public void haveFun() {
System.out.println("韩非子大吼一声:侍寝!");
setChanged();
notifyObservers("韩非子开始娱乐了");
}
}
观察者
观察者一
class LiSi implements Observer {
@Override
public void update(Observable observable, Object obj) {
//李斯是个观察者,一旦韩非子有活动,他就收到了谍报
System.out.println("【李斯】报告秦老板!臣收到谍报,韩非子有新动向--->" + obj.toString());
}
}
观察者二
class MrsHan implements Observer {
public void update(Observable observable, Object obj) {
System.out.println("【韩夫人】因为--->" + obj.toString() + "——所以我悲伤呀");
}
}
演示
public class Test {
public static void main(String[] args) {
//定义被观察者
HanFeiZi hanFeiZi = new HanFeiZi();
//定义观察者
Observer liSi = new LiSi();
Observer mrsHan = new MrsHan();
//观察者注册被观察者
hanFeiZi.addObserver(liSi);
hanFeiZi.addObserver(mrsHan);
//然后观察者就可以监视被观察者韩非子的动向
hanFeiZi.haveBreakfast();
hanFeiZi.haveFun();
}
}
2018-2-21
Observer 观察者模式的更多相关文章
- C++设计模式-Observer观察者模式
Observer观察者模式作用:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己 UML图: S ...
- 委托、事件、Observer观察者模式的使用解析二
一.设计模式-Observer观察者模式 Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新.Observer模式是一种 ...
- Observer观察者模式与OCP开放-封闭原则
目录 场景引入 在联网坦克项目中使用观察者模式 总结 在学习Observer观察者模式时发现它符合敏捷开发中的OCP开放-封闭原则, 本文通过一个场景从差的设计开始, 逐步向Observer模式迈进, ...
- Observer 观察者模式 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- 设计模式18:Observer 观察者模式(行为型模式)
Observer 观察者模式(行为型模式) 动机(Motivation) 在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”——一个对象(目标对象)的状态发生改变,所有依赖对象(观察者对象) ...
- java设计模式解析(1) Observer观察者模式
设计模式系列文章 java设计模式解析(1) Observer观察者模式 java设计模式解析(2) Proxy代理模式 java设计模式解析(3) Factory工厂模式 java设计模式解析( ...
- observer观察者模式
观察者模式(有时又被称为发布-订阅Subscribe>模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有观察者对象,让 ...
- 设计模式 ( 十七 ):Observer 观察者模式 -- 行为型
1.概述 一些面向对象的编程方式,提供了一种构建对象间复杂网络互连的能力.当对象们连接在一起时,它们就可以相互提供服务和信息. 通常来说,当某个对象的状态发生改变时,你仍然需要对象之间能互相通信.但是 ...
- HeadFirst设计模式 之 C++实现(二):Observer(观察者模式)
观察者模式是最经常使用的设计模式之中的一个,[对象之间多对一的依赖关系,当一个对象发生变化时,其会通知全部依赖它的对象].拿订阅报纸和发行报社打例如,报社採集到news制作新的报纸,派送给订阅的客户. ...
随机推荐
- Notepad++插件之FingerText
FingerText是一个标签触发片段插件记事本.支持多个热点同时编辑,嵌套的热点,动态热点(很多不仅仅是纯文本的,可以通过命令,或触发另一个片段中的片段),热点的文本提示(而不是仅仅是$或#号)和热 ...
- DataNode工作原理(四)
DataNode的作用:提供真实文件数据的存储服务.以文件块进行存储. 文件块(block):最基本的存储单位.对文件内容而言,一个文件的长度大小是size,那么从文件的0偏移开始,按照固定的大小,顺 ...
- android 学习第一步
今天是2015年7月24号,今年下半年的主要学习方向是android,学习的目标是做出3个或以上的有实用价值的app.
- 跨平台的zip文件压缩处理,支持压缩解压文件夹
根据minizip改写的模块,需要zlib支持 输出的接口: #define RG_ZIP_FILE_REPLACE 0 #define RG_ZIP_FILE_APPEND 1 //压缩文件夹目录, ...
- 错误: 找不到或无法加载主类 scala.tools.nsc.MainGenericRunner
错误: 找不到或无法加载主类 scala.tools.nsc.MainGenericRunner 原因: Sacala安装路径中包含空格.
- Unity3d webplayer发布的问题和100%自适应浏览器
Unity3d发布的问题 发布的时候,遇到无法写入Resources.assets,原来是我的项目中有多个Resources文件夹,以后最好是不要有重复的文件夹和一样名字的资源! 还有就是发布的web ...
- 模态运行EXE程序
function ExecShowModal(APath: PChar; ACmdShow: Integer; ATimeout: Longword): Integer; var vStartupIn ...
- Spark应用程序的运行框架
几个基本概念: (1)job:包含多个task组成的并行计算,往往由action催生. (2)stage:job的调度单位. (3)task:被送到某个executor上的工作单元. (4)taskS ...
- 对于唯一索引使用唯一条件搜索, InnoDB 只锁定找到的index record,不是它之前的区间
| test100 | CREATE TABLE `test100` ( `sn` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增编号', `phoneNo` ...
- HTTP请求和响应详解
HTTP有两部分组成:请求与响应,下面分别整理. 一.HTTP请求 1.HTTP请求格式: <request line> <headers> <blank line> ...