一、什么是Observer模式

在Observer模式中,当观察对象的状态发生变化时,会通知给观察者。Observer模式适用于根据对象状态进行相应处理的场景。

简单一句话概况就是:观察者会发送观察对象状态变化的通知。

二、Observer模式示例代码

下面示例程序中,observer将观察一个会生成数值的对象,并将它生成的数值结果显示出来。不过,不同的观察者的显示方式不一样。Digitobserver会以数字形式显示数值,而Graphobserver则会以简单的图示形式来显示数值。

2.1 各个类之间的关系

先看一下所有的类和接口:

类图:

2.2 Observer接口

Observer接口是表示“观察者”的接口。具体的观察者会实现这个接口。

用于生成数值的NumberGenerator类会调用update方法,将“生成的数值发生了变化,请更新显示内容”的通知发送给Observer。

public interface Observer {public abstract void update(NumberGenerator generator);
}

2.3 NumberGenerator类

NumberGenerator类(代码清单17-2)是用于生成数值的抽象类。生成数值的方法( execute方法)和获取数值的方法( getNumber方法)都是抽象方法,需要子类去实现。

addObserver方法用于注册observer,而deleteobserver方法用于删除observer。

notifyObservers方法会向所有的observer发送通知,告诉它们“我生成的数值发生了变化,请更新显示内容”。该方法会调用每个observer的update方法。

public abstract class NumberGenerator {//用于保存所有的observerprivate ArrayList observers = new ArrayList();//注册observerpublic void addObserver(Observer observer) {observers.add(observer);}//删除observerpublic void deleteObserver(Observer observer) {observers.remove(observer);}//向observer发送通知public void notifyObservers() {//把每个observer拿出来,调用他的update方法Iterator it = observers.iterator();while (it.hasNext()) {Observer o = (Observer) it.next();o.update(this);}}//获取数值public abstract int getNumber();//生成数值public abstract void execute();
}

2.4 RandomNumberGenerator类

RandomNumberGenerator类是NumberGenerator的子类,它会生成随机数。

getNumber方法用于获取number字段的值。execute方法会生成20个0 ~49的随机整数,并通过notifyObservers方法把每次生成结果通知给观察者。

public class RandomNumberGenerator extends NumberGenerator{//生成随机数private Random random  = new Random();//当前数值private int number;@Overridepublic int getNumber() {return number;}@Overridepublic void execute() {for (int i = 0; i < 20; i++) {number = random.nextInt(50);notifyObservers();}}
}

2.5 DigitObserver类

DigitObserver类实现了Observer接口,它的功能是以数字形式显示观察到的数值。

它的update方法接收NumberGenerator的实例作为参数,然后通过调用NumberGenerator类的实例的getNumber方法可以获取到当前的数值,并将这个数值显示出来。

public class DigitObserver implements Observer{@Overridepublic void update(NumberGenerator generator) {System.out.println("DigitObserver:" + generator.getNumber());try {Thread.sleep(100);} catch (InterruptedException e) {}}
}

2.6 GraphObserver类

GraphObserver类也实现了Observer接口。

该类会将观察到的数值以*****这样的简单图示的形式显示出来。

public class GraphObserver implements Observer{@Overridepublic void update(NumberGenerator generator) {System.out.println("GraphObserver:");int count = generator.getNumber();for (int i = 0; i < count; i++) {System.out.print("*");}System.out.println("");try {Thread.sleep(100);} catch (InterruptedException e) {}}
}

2.7 Main测试类

Main类生成了一个RandomNumberGenerator类的实例和两个观察者,其中observer1是 DigitObserver类的实例,observer2是GraphObserver类的实例。

在使用addObserver注册观察者后,它还会调用generator.execute方法生成随机数值。

public class Main {public static void main(String[] args) {NumberGenerator generator = new RandomNumberGenerator();Observer observer1 = new DigitObserver();Observer observer2 = new GraphObserver();generator.addObserver(observer1);generator.addObserver(observer2);generator.execute();}
}

2.8 运行结果

部分运行结果

DigitObserver:21
GraphObserver:
*********************
DigitObserver:7
GraphObserver:
*******
DigitObserver:31
GraphObserver:
*******************************
DigitObserver:24
GraphObserver:
************************

三、拓展思路的要点

3.1 可替换性

使用设计模式的目的之一就是使类成为可复用的组件。

在Observer模式中,有带状态的ConcreteSubject角色和接收状态变化通知的ConcreteObserver角色。连接这两个角色的就是它们的接口(API ) Subject角色和 Observer 角色。

一方面RandomNumberGenerator类并不知道,也无需在意正在观察自己的(自己需要通知的对象)到底是DigitObserver类的实例还是GraphObserver类的实例。不过它知道在它的observers字段中所保存的观察者们都实现了observer接口,一定可以调用它们的update方法。

另一方面,DigitObserver类也无需在意自己正在观察的究竟是RandomNumberGenerator类的实例还是其他XxxxNumberGenerator类的实例。不过,Digitobserver类知道它们是NumberGenerator类的子类的实例,并持有getNumber方法。

我们应该注意到这种可替换性的思想:

  • 利用抽象类和接口从具体类中抽出抽象方法

  • 在将实例作为参数传递至类中,或者在类的字段中保存实例时,不使用具体类型,而是使用抽象类型和接口

这样的实现方式可以帮助我们轻松替换具体类。

3.2 从“观察”变为“通知”

Observer本来的意思是“观察者”,但实际上Observer角色并非主动地去观察,而是被动地接受来自Subject角色的通知。因此,Observer模式也被称为Publish-Subscribe(发布-订阅)模式。个人认为Publish(发布)和 Subscribe(订阅)这个名字可能更加合适。

四、相关的设计模式

4.1 Mediator中介者模式

在Mediator模式中,有时会使用Observer模式来实现Mediator角色与Colleague角色之间的通信。

就“发送状态变化通知”这一点而言,Mediator模式与Observer模式是类似的。不过,两种模式中,通知的目的和视角不同。

在 Mediator模式中,虽然也会发送通知,不过那不过是为了对Colleague角色进行仲裁而已。

而在Observer模式中,将Subject角色的状态变化通知给Observer角色的目的则主要是为了使Subject角色和 Observer角色同步。

设计模式学习(二):Observer观察者模式相关推荐

  1. 设计模式学习(二): 观察者模式 (C#)

    <深入浅出设计模式>学习笔记第二章 需求: 开发一套气象监测应用,如图: 气象站,目前有三种装置,温度.湿度和气压感应装置. WeatherData对象追踪气象站的数据,并更新到布告板,布 ...

  2. Unity游戏设计模式(二)观察者模式(Observer Pattern)

    最近看游戏设计模式,当看到观察者模式时被搞得云里雾里的,什么观察者,被观察者,抽象观察者,抽象被观察者.听着这些词就觉得可怕,其实理解以后还是比较简单的. 当我们玩游戏时,经常会出现一些事件,而这个事 ...

  3. 设计模式笔记 18. Observer 观察者模式(行为型模式)

    18. Observer 观察者模式                     2008-09-15 动机(Motivation) 在软件构建过程中,我们需要为某些对象建立一种"通知依赖关系& ...

  4. HeadFirst 设计模式(二)观察者模式(Observer Pattern)

    观察者模式(Observer Pattern) 在对象之间建立一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新. 设计原则 找出应用中可能需要变化之处,把它们独立出来, ...

  5. 设计模式(二)————观察者模式

    引言 观察者模式可以说是JDK中使用最多的模式之一,这个模式可以让你的对象随时随地的了解想要知道的情况,你还可以让某个对象在运行时决定是否要继续通知:观察者模式的定义为: 定义对象间一种一对多的依赖关 ...

  6. 【三】Java 设计模式学习记录:观察者模式

    文章目录 一.观察者模式(行为型模式) 1.1 场景 1.2 普通解决方案 1.3 观察者模式定义 1.4 观察者模式原理 二.代码实现 2.1 代码结构 2.2 上代码 2.3 扩展性 三. 框架应 ...

  7. 常人能看懂的设计模式(二)观察者模式

    初衷: 最近一直在研究设计模式,主要以专研<Head First设计模式>以及看网上各路大神的见解.这边想用自己对于23种设计模式的理解,用一种非程序员都能理解的方式去介绍设计模式,毕竟我 ...

  8. 结合项目实例 回顾传统设计模式(二)观察者模式

    观察者模式现在用的不是很多 重点看下它的设计思想 OK 下面继续 消息中心的那点事 /// <summary>     /// 数据中心     /// </summary> ...

  9. 设计模式 ( 十七 ):Observer 观察者模式 -- 行为型

    1.概述 一些面向对象的编程方式,提供了一种构建对象间复杂网络互连的能力.当对象们连接在一起时,它们就可以相互提供服务和信息. 通常来说,当某个对象的状态发生改变时,你仍然需要对象之间能互相通信.但是 ...

  10. Java设计模式(二) 观察者模式

    观察者模式: 定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖者都会受到通知并自动更新. 1,定义事件源接口 package com.pattern.observer;publ ...

最新文章

  1. 关注:诺奖得主被爆40多篇论文P图造假!涉及国内“杰青”
  2. SQL Server 2005 连接本地端口1433开启远程连接/登陆18456错误的解决方法
  3. Glide 源码分析与面试提问
  4. Java开发面试技巧,Hive-JDBC操作
  5. uva1025城市里的间谍
  6. 《大数据算法》一1.2 大数据算法
  7. Android Binder Driver缺陷导致定屏问题分析
  8. centos 7.9密码改密钥登陆
  9. 【转】【UML】使用Visual Studio 2010 Team System中的架构师工具(设计与建模)
  10. FineReport 11.0 五大全新功能,让报表开发更快、更好看
  11. 运营九年,这款音乐手游宣布停服!将从应用商店下架...
  12. bzoj 1659: [Usaco2006 Mar]Lights Out 关灯(IDA*)
  13. IDEA运行main,junit方法报错Class not found
  14. 灵光一闪-(面对对象实践)
  15. 笔记本电池检测工具 BatteryInfoView 汉化
  16. 删除卸载企业微信后的残留文件
  17. 计算机图形学中点画线法
  18. 如何将txt、excel文档里面的电话号码快速转换为vcf格式的电话簿导入手机
  19. 概率论复习笔记二——离散型分布和连续型分布
  20. 行业前沿|无人机视觉自主导航发展及视觉智能开发支撑平台介绍

热门文章

  1. 数据库中between的使用方法
  2. 一个简单的网络应用——面部拍照软件
  3. latex设置itemize形式以及多层itemize
  4. python:实现合并多张图片成视频(附完整源码)
  5. 为什么35岁以后的中年人,会对自己的未来无比焦虑?
  6. UML基本介绍与UML类图
  7. c 语言结构的作用是什么意思,c语言里面的结构体是什么意思
  8. biginteger 原理_BigInteger详解
  9. lumen认证中出现unauthorized._网工知识角|一分钟搞定802.1x认证配置,了解三种授权模式的区别...
  10. 冷光美白仪器 使用说明 美白牙齿