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制作新的报纸,派送给订阅的客户. ...
随机推荐
- jupyter notebook 小技巧
Converting notebooks to other formats¶ !pip install https://github.com/ipython-contrib/jupyter_contr ...
- 关于CSRF的那点事儿
0x01 CSRF简介 CSRF,也称XSRF,即跨站请求伪造攻击,与XSS相似,但与XSS相比更难防范,是一种广泛存在于网站中的安全漏洞,经常与XSS一起配合攻击. 0x02 CSRF原理 ...
- Elasticsearch源码分析 | 单节点的启动和关闭
本文主要简要介绍Elasticsearch单节点的启动和关闭流程.Elasticsearch版本:6.3.2 相关文章 1.Google Guice 快速入门 2.Elasticsearch 中的 G ...
- 同步VDP时间
使用yast 进入蓝屏界面,修改system—date and time,取消hardware clock set to utc,时区设置为上海或者北京,然后sntp -r 时间服务器地址 敲击syn ...
- [ 原创 ]Centos 7.0下安装 Tomcat8.5.15
Tomcat下载地址:http://tomcat.apache.org/download-80.cgi#8.5.15 上传到文件夹 并解压缩 出现问题: 解决方法: http://blog.csdn. ...
- C++下的强制转换类型
一.static_cast static_cast,静态类型转换. 下面,我举几个例子,大家就能清楚了. int main(int argc, char const *argv[]) { char ...
- bzoj 3837 (随机过题法了解一下)
3837: [Pa2013]Filary Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 395 Solved: 74[Submit][Status] ...
- [HihoCoder1596]Beautiful Sequence
题目大意: \(n(n\le60)\)个数\(A_{1\sim n}\),将这些数随机打乱,问最后构成的数列满足对于所有的\(2\le i\le n-1\),都有\(2A_i\le A_{i-1}+A ...
- JS实现背景透明度可变,文字不透明的效果
最近项目里需要实现这么个功能,类似网游中的聊天框,背景都是透明的,但是文字是不透明.所以如果简单的使用opacity(非IE)和alpha滤镜(IE)是无法实现这个效果的,会造成全部透明. 解决办法如 ...
- 【Go入门教程7】面向对象(method、指针作为receiver、method继承、method重写)
前面两章我们介绍了函数和struct,那你是否想过函数当作struct的字段一样来处理呢?今天我们就讲解一下函数的另一种形态,带有接收者(receiver)的函数,我们称为method method ...