Observer 观察者模式 MD
| 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 观察者模式 MD的更多相关文章
- C++设计模式-Observer观察者模式
Observer观察者模式作用:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己 UML图: S ...
- Observer 观察者模式
简介 观察者模式(Observer),有时又被称为[发布]publish-[订阅]Subscribe模式.模型-视图(View)模式.源-收听者(Listener)模式或从属者模式.在此种 ...
- 委托、事件、Observer观察者模式的使用解析二
一.设计模式-Observer观察者模式 Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新.Observer模式是一种 ...
- Observer观察者模式与OCP开放-封闭原则
目录 场景引入 在联网坦克项目中使用观察者模式 总结 在学习Observer观察者模式时发现它符合敏捷开发中的OCP开放-封闭原则, 本文通过一个场景从差的设计开始, 逐步向Observer模式迈进, ...
- 设计模式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制作新的报纸,派送给订阅的客户. ...
随机推荐
- java 将class打包成jar包
一.进入到java jdk安装目录(用cmd命令进入) c:cd C:\Program Files\Java\jdk1.8.0_45\bin 二.运行打包命令(将D盘下com中的class 打包成xy ...
- 20172304 实验二 《Java面向对象程序设计》 实验报告
20172304 实验二 <Java面向对象程序设计> 实验报告 课程名称:<程序设计与数据结构> 学生班级:1723班 学生姓名:段志轩 学生学号:20172304 实验时间 ...
- NCPC 2016 October 8,2016 Artwork
Problem A Artwork Problem ID: artwork Time limit: 4 seconds A template for an artwork is a white gri ...
- 在(Raspberry Pi)树莓派上安装NodeJS
本文主讲如何在树莓派3B上安装node.js 环境描述1. 树莓派安装了`2016-11-25-raspbian-jessie-lite`(PS:在此版本的镜像中,默认禁用了ssh,在烧录好镜像之后, ...
- CSS3组件化之菊花loading
<div class="juhua-loading"> <div class="jh-circle"></div> < ...
- keystone 认证深度研究分析
一.Keystone Token深度概述 Keystone作为OpenStack项目基础认证模块,目前支持的token类型分别是uuid.pkiz.pki.fernet. 首先,简要叙述一下这四种类型 ...
- mysql常见知识点
最近整理了一些数据库常见的面试题,对自己也是个复习,希望对大家也有所帮助. 1.触发器的作用? 触发器是一类特殊的存储过程,主要是通过事件来触发而被执行的.它可以强化约束,来维护数据的完整性和一致性, ...
- 深入理解ajax系列第八篇
前面的话 在以前,网站的用户与后端交互的主要方式是通过HTML表单的使用.表单的引入在1993年,由于其简单性和易用性,直到电子商务出现之前一直保持着重要位置.理解表单提交,对于更深入地理解ajax是 ...
- [BZOJ4699]树上的最短路(最短路+线段树)
https://www.cnblogs.com/Gloid/p/10273902.html 这篇文章已经从头到尾讲的非常清楚了,几乎没有什么需要补充的内容. 首先$O(n\log^2 n)$的做法比较 ...
- [POI2015]Pieczęć
[POI2015]Pieczęć 题目大意: 一张\(n\times m(n,m\le1000)\)的方格纸,有些格子需要印成黑色,剩下的格子需要保留白色. 你有一个\(a\times b(a,b\l ...