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制作新的报纸,派送给订阅的客户. ...
随机推荐
- python opencv3 grabcut前景检测
git:https://github.com/linyi0604/Computer-Vision import numpy as np import cv2 import matplotlib.pyp ...
- CVE-2014-4113本地提权测试
CVE-2014-4113本地提权漏洞分析 By Netfairy 前言 2014年10月14日, Crowdstrike和FireEye发表了一篇文章, 描述了一个新的针对Windows的提权漏洞. ...
- BZOJ2716 KD-Tree
好久没写博客了 回去赶了好久文化课 颓欲见长 突然翻到fc爷的KD-Tree板子 来切了到裸题 对于一开始的数据我们可以先预处理 具体的排序方式见板子 其实就是我们对每次选定的一块选一个维度来排序啦 ...
- 改变手机浏览器(iPhone/Android)上文本输入框的默认弹出键盘
iPhone/iPad和Android提供不同的的键盘输入类型,触发合适的键盘将极大地改善用户体验. 键盘类型 默认: 默认键盘的字母模式 数字: 默认键盘的数字模式,(含小数点等) 邮件: 与默 ...
- Codeforces Round #FF (Div. 1) A. DZY Loves Sequences 动态规划
A. DZY Loves Sequences 题目连接: http://www.codeforces.com/contest/446/problem/A Description DZY has a s ...
- UVALive 4869 Profits DP
G - Profits Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu Submit Status ...
- 处理 CALayer 变形后的抗锯齿问题
处理锯齿当然要用抗锯齿,iOS 可以通过修改 Plist 实现全局抗锯齿,但是这样容易出现性能问题. 所以就要使用对单个 Layer 开启抗锯齿的方法 layer.allowsEdgeAntialia ...
- ASP.NET 构建高性能网站 架构设计
Web前端系统 为了达到不同应用的服务器共享.避免单点故障.集中管理.统一配置等目的,不以应用划分服 务器,而是将所有服务器做统一使用,每台服务器都可以对多个应用提供服务,当某些应用访问量升高时,通过 ...
- 华为S5300系列交换机V100R006SPH017VRP热补丁
S5300_V100R006SPH017.pat 附件: 链接:https://pan.baidu.com/s/16lrNMykatXR3_5xKBc2zuw 密码:rt1l
- 通过maven-war-plugin插件对war包分环境打包
针对多环节,从源头打包入手,当然这些都可以在运维阶段用脚本进行替换来代替 resources/environment/下有四个环境,local本地.dev开发.test测试.pre预上线.prod生产 ...