一, 观察者模式(Observer) 的定义

观察者模式:   定义了一种 1对多 的依赖关系, 让多个观察者对象同时监听1个主题对象.

这个主题对象在状态发生变化时, 会通知所有的观察者对象, 使它们能够同时更新自己.

稍微解释一下 这个1 对多 的依赖关系.

1对多 这个关键词我们常常在DB 表设计里提到,  但是这里的意思是有点区别的.

首先,  1 是1个对象, 而不是1个类,     而多也是指多个对象, 而不是多个类.

其次,  这里的多个对象可以是多个不同的类的对象.  甚至是毫无关系的多个类.

再次, 这个依赖关系, 到底是1个对象依赖多个对象, 还是多个对象依赖1个对象呢.

在这里的定义来讲答案是后者.

但是, 实际上, 1个观察者也可以观察多个被观察者的. (但这就不属于观察者模式了)

所以, 观察者模式(Observer) 也叫做 发布-订阅模式(publish/Subscribe).

相当与, 多个读者同时收听1个电台.

二, 观察者模式(Observer) 的各个角色.

首先睇下Observer 模式的标准UML图.

我们大概得出上图有4个角色.

2.1 Observer (观察者)

Observer是1个接口, 我们可以理解它是1个抽象观察者类.

它只有1个update()方法, 也就是说它可以通过这个方法来执行某些动作.

2.2 Subject (通知者/被观察者)

Subject是1个接口, 我们可以理解为1个抽象被观察者类.

我们可以见到它有5个方法.

attach() 和 detach()方法用来增删观察者的数量, 也就是指当前被观察者对象到底有多少个观察者在观察着它.

setState(), 和 getState() 用于获取和设置通知者对象本身的状态, 这个状态通常是传送给观察者们的信息或参数.

也就是说观察者模式到底在观察什么. 无非就是观察被观察者的这个状态.

Notify(),  被观察者通知所有观察者, 让观察者根据自己的当前状态(getState())执行自己的update()方法

2.3 ConcreteSubject (具体通知者/被观察者)

这个(些)就是具体的被观察者类, 只要实现了Subject接口, 就可以添加1些对象作为自己的观察者(或者叫粉丝啦)

写到这里, 大家都会了解到, 这个类里面肯定有1个容器, 用于存放观察者的对象.

这个容器可以根据需要由具体的被观察者选择, 通常是无序不能重复的Set容器(例如 HashSet)

而Notify()方法无非就是遍历自己的观察者容器, 逐个执行观察者的update()方法.

2.4 ConcreteObserver (具体观察者类)

这些类可以是毫无关联的类, 但是它们都必须实现Observer接口

一旦这些对象被通知者, 加入自己的容器, 就相当于观察者正在观察某个被观察者.

注意,  观察者可以被多个被观察者加入自己的容器, 也就是相当于观察了多个被观察者了.(但这就break了观察者模式)

三, 1个具体例子和代码.

下面我们用1个具体例子来简单实现这个模式.

我们假定1个事件有3个角色.

1. 指挥者.(Commander)

指挥炮手打炮, 他可以让让 若干个炮手和炮灰纳入自己的命令范围.

2. 炮手, (CannonShooter)

一旦指挥者通知目标, 若干个炮手就往哪个目标轰击.

3. 炮灰 (CannonFodder)

一旦指挥者通知, 炮灰就趴下..

也就是说, 炮手必须知道指挥这的状态(目标信号), 到底打谁.

而炮灰是无序关心到底打哪里的, 一旦接到通知, 趴下就是了.

3.1 UML图

3.2 Subject接口 代码

public interface Subject {public void attach(Observer obs);public void detach(Observer obs);public void sNotify();   //notify is a finel method of Object classpublic int  getState();public void setState(int state);
}

5个方法的意义上面已经解释过了.

通知方法之所以不写成notify(), 是因为notify()本身是Object类的1个finel方法

3.2 Observer接口 代码

public interface Observer {public void update();
}

只有1个抽象方法update()

3.3 Commander 类 代码

import java.util.HashSet;
import java.util.Iterator;
public class Commander implements Subject{private int targetPlaceID;private HashSet<Observer> gunnerSet = new HashSet<Observer>();@Overridepublic void attach(Observer obs){this.gunnerSet.add(obs);}@Overridepublic void detach(Observer obs) {this.gunnerSet.remove(obs);}@Overridepublic void sNotify() {if (this.gunnerSet.isEmpty()){return;}Iterator itr = this.gunnerSet.iterator();while (itr.hasNext()){Observer obs = (Observer)itr.next();obs.update();}}@Overridepublic int getState() {// TODO Auto-generated method stubreturn this.targetPlaceID;}@Overridepublic void setState(int state) {// TODO Auto-generated method stubthis.targetPlaceID = state;}}

它重写了接口所有方法.

所谓的notify()方法, 无非就是遍历自己容器的所有观察者, 该干嘛的干嘛(遍历调用它们的update())方法

3.4 CannonShooter 类 代码

public class CannonShooter implements Observer{private Subject cmder;public CannonShooter(Subject cmder){this.cmder = cmder;}public Subject getCmder() {return cmder;}public void setCmder(Subject cmder) {this.cmder = cmder;}public void fireCannon(int targetPlace){System.out.println(this.getClass().getSimpleName() + ": fired on target(id:" + targetPlace + ") by Cannon");}@Overridepublic void update() {// TODO Auto-generated method stubfireCannon(cmder.getState());}
}

可以见到,  炮手必须知道指挥者的状态信息, 所以它里面必须有个当前指挥者的对象成员.

3.5 CannonFodder 类 代码

public class CannonFodder implements Observer{private int id;public CannonFodder(int id){this.id = id;}public void getDown(){System.out.println(this.getClass().getSimpleName() +" id:"+ this.id + " getDowned");}@Overridepublic void update() {// TODO Auto-generated method stubthis.getDown();}
}

炮灰无需关心指挥者的状态, 里面只需要重写自己的update()方法就ok.

3.6 CannonFodder 类 代码

public class ClientObserver {public static void f(){Commander cmder = new Commander();CannonShooter cster = new CannonShooter(cmder);CannonFodder cfder1 = new CannonFodder(1);CannonFodder cfder2 = new CannonFodder(2);CannonFodder cfder3 = new CannonFodder(3);cmder.setState(107);cmder.attach(cster);cmder.attach(cfder1);cmder.attach(cfder2);cmder.attach(cfder3);cmder.sNotify();cmder.setState(108);cmder.detach(cfder3);cmder.sNotify();}
}

上面的代码不难看懂.

无非就是实例化1个指挥者, 1个炮手, 3个炮灰

首先, 指挥者通知向107目标打炮,   炮手射了, 3个炮灰趴下了.

后来指挥者想向打击108目标, 但是觉得第3号炮灰不在攻击范围,   所以从自己的观察者容器里移除3号炮灰.

这时, 炮手向108号目标打击,  只有1号2号炮灰听指挥爬下.

相当灵活.

四, 观察者模式的特点和应用范围.

4.1 Observer模式的特点

上面的例子中, 观察者和被观察者的耦合性不大.

1个subject可以有任意数目的观察者Observer,  程序猿令subject发出通知时根本无需知道观察者是谁, 有多少观察者存在.

而单个观察者本身也无需知道到底有几个其他观察者同时存在.

4.2 什么时候应该使用Observer模式

很明显嘛,  就是当1个对象发生改变的同时需要同时改变其他多个对象时.

而且, 观察者模式令到耦合的双方, 依赖与接口(抽象), 而不是依赖于具体(非抽象类), 符合封闭-开放模式.

观察者模式(Observer) 简介相关推荐

  1. 设计模式:观察者模式--Observer

    一.什么是观察者模式 1.生活中的观察者模式 1.警察抓小偷 在现实生活中,警察抓小偷是一个典型的观察者模式「这以一个惯犯在街道逛街然后被抓为例子」,这里小偷就是被观察者,各个干警就是观察者,干警时时 ...

  2. 设计模式 ( 十六 ) 观察者模式Observer(对象行为型)

    设计模式 ( 十五 ) 观察者模式Observer(对象行为型) 1.概述 一些面向对象的编程方式,提供了一种构建对象间复杂网络互连的能力.当对象们连接在一起时,它们就可以相互提供服务和信息. 通常来 ...

  3. 观察者模式 Observer 发布订阅模式 源 监听 行为型 设计模式(二十三)

    观察者模式 Observer 意图 定义对象一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖他的对象都得到通知并自动更新. 别名:依赖(Dependents),发布订阅(Publish-Su ...

  4. java设计模式--观察者模式(Observer)

    java设计模式--观察者模式(Observer) java设计模式--观察者模式(Observer) 观察者模式的定义: 定义对象间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖于它的 ...

  5. c++观察者模式observer

    c++观察者模式observer 概念 角色和职责 典型应用 案例 概念 Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态. Obs ...

  6. Javascript乱弹设计模式系列(1) - 观察者模式(Observer)

    前言 博客园谈设计模式的文章很多,我也受益匪浅,包括TerryLee.吕震宇等等的.NET设计模式系列文章,强烈推荐.对于我,擅长于前台代码的开发,对于设计模式也有一定的了解,于是我想结合Javasc ...

  7. 设计模式 - 观察者模式(Observer Pattern) Java内置 用法

    观察者模式(Observer Pattern) Java内置 用法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26601659 ...

  8. 设计模式初探-观察者模式(OBSERVER)又称发布-订阅(Publish-Subscribe)依赖(Dependents)

    观察者模式(OBSERVER),又称发布-订阅(Publish-Subscribe),依赖(Dependents),通过定义对象间的一对多的依赖关系,达到当一个对象的状态发生改变时,所有依赖于它的对象 ...

  9. Android开发中常见的设计模式深入浅出——观察者模式Observer

    ##最近老大写的Android项目里用到了RxBus然后我就去百度了 让我先了解RxJava 然后RxJava又是由观察者模式的变种写的 所以打算从头学一遍!!! 观察者模式 Observer 顾名思 ...

最新文章

  1. 【Ubuntu】使用过的ubuntu工具记录
  2. HTTP深入浅出 http请求
  3. Android ADB Server启动失败
  4. 牛客网 暑期ACM多校训练营(第一场)J.Different Integers-区间两侧不同数字的个数-离线树状数组 or 可持久化线段树(主席树)...
  5. 143. Reorder List
  6. Spark _18 _Shuffle文件寻址
  7. 分页类实例 java
  8. 无数踩坑系列(3)-配置pytorch
  9. Java面试题:面向对象的特征有哪些方面?
  10. Java面试八股文(素材来自网络)
  11. BOS v2.0后台管理系统 JQuery Easyui 相关知识讲解
  12. 好用的倒计时APP 可以同时开多个倒数计时器的便签
  13. JavaScript模式(1):字面量和构造函数
  14. 每日一记录,2022年1月5日
  15. 从 Google 离职了!
  16. Android 各国语言包字符串缩写
  17. 数据可视化之美-动态图绘制【补充】(以Python为工具)
  18. PaddleOCR,图像检测识别
  19. vCenter Server CA证书下载
  20. uni-app小说阅读页,vue小说阅读页,静态demo

热门文章

  1. 数据结构--稀疏矩阵的一种实现
  2. GPTEE中的Crypto API的使用
  3. CSocket类的Receive超时的问题解决方案
  4. (42)驱动中使用全局变量
  5. (33)调试驱动程序
  6. python2 去除 字符串中emoji 符号,去除所有4字节utf8字符
  7. Docker-compose 安装配置 Nginx PHP MySQL Laravel
  8. 牛客竞赛语法入门班数组字符串习题【完结】
  9. 1059 Prime Factors (25 分)【难度: 一般 / 知识点: 分解质因子 】
  10. docker之网络访问