观察者模式又叫做发布-订阅模式(Publish.Subscribe)模式、模型-视图模式(Model/View)模式、源-监听器模式(Source/Listener)模式或从属者(Dependents)模式。

  观察者模式定义了一种一对多的依赖关系,让多个观察者同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

1.  观察者模式结构

一个简单的观察者模型如下:

角色:

抽象(Subject)主题角色:把所有的观察者维持在一个集合中,每个主题都可以有任意数量的观察者。提供一个接口,可以增加和删除观察者,主题角色又叫做被观察者(Observable)。

抽象观察者(Observer)角色:在得到主题的通知时更新自己。有时候观察者依赖于被观察者,可以将update方法修改为 void update(Subject subject)。

具体主题角色:维护所有的观察者,在具体主题的内部状态改变时给所有登记的观察者发送通知。

具体观察者角色:存储与主题的状态自恰的状态,也就是随着主题的状态改变自己的状态。

代码如下:

  1. package cn.qlq.observer;
  2.  
  3. public interface Subject {
  4. void attach(Observer observer);
  5.  
  6. void delete(Observer observer);
  7.  
  8. void notifyObservers();
  9. }
  1. package cn.qlq.observer;
  2.  
  3. import java.util.Enumeration;
  4. import java.util.List;
  5. import java.util.Vector;
  6.  
  7. public class ConcreteSubject implements Subject {
  8.  
  9. private List<Observer> observers = new Vector<>();
  10.  
  11. @Override
  12. public void attach(Observer observer) {
  13. observers.add(observer);
  14. }
  15.  
  16. @Override
  17. public void delete(Observer observer) {
  18. observers.remove(observer);
  19. }
  20.  
  21. @Override
  22. public void notifyObservers() {
  23. for (Observer observer : observers) {
  24. observer.update();
  25. }
  26. }
  27.  
  28. }
  1. package cn.qlq.observer;
  2.  
  3. public interface Observer {
  4.  
  5. /**
  6. *
  7. */
  8. void update();
  9.  
  10. }
  1. package cn.qlq.observer;
  2.  
  3. public class ConcreteObserver implements Observer {
  4.  
  5. @Override
  6. public void update() {
  7. System.out.println(" i am notified");
  8. }
  9.  
  10. }

2.  第二种实现

  考虑上面的主题中,管理维护观察者集合的方法可以放到抽象类中去实现,因此可以将维护观察者关系的代码抽取到抽象类中,类图如下:

  这种方式与上面的区别是代表存储观察者对象的集合从连线是从抽象主题到抽象观察者。(也就是抽象主体维护抽象观察者的引用关系)

代码如下:

  1. package cn.qlq.observer;
  2.  
  3. import java.util.List;
  4. import java.util.Vector;
  5.  
  6. public abstract class Subject {
  7. private List<Observer> observers = new Vector<>();
  8.  
  9. public void attach(Observer observer) {
  10. observers.add(observer);
  11. }
  12.  
  13. public void delete(Observer observer) {
  14. observers.remove(observer);
  15. }
  16.  
  17. public void notifyObservers() {
  18. for (Observer observer : observers) {
  19. observer.update();
  20. }
  21. }
  22. }
  1. package cn.qlq.observer;
  2.  
  3. public class ConcreteSubject extends Subject {
  4.  
  5. private String state;
  6.  
  7. public void changeState(String newState) {
  8. state = newState;
  9. this.notifyObservers();
  10. }
  11.  
  12. }
  1. package cn.qlq.observer;
  2.  
  3. public interface Observer {
  4.  
  5. /**
  6. *
  7. */
  8. void update();
  9.  
  10. }
  1. package cn.qlq.observer;
  2.  
  3. public class ConcreteObserver implements Observer {
  4.  
  5. @Override
  6. public void update() {
  7. System.out.println(" i am notified");
  8. }
  9.  
  10. }

客户端测试代码:

  1. package cn.qlq.observer;
  2.  
  3. public class Client {
  4.  
  5. public static void main(String[] args) {
  6. ConcreteSubject subject = new ConcreteSubject();
  7. Observer observer = new ConcreteObserver();
  8.  
  9. subject.attach(observer);
  10.  
  11. subject.changeState("1");
  12. }
  13.  
  14. }

3.  Java语言对观察者模式的支持

  在Java.util保重中,提供了一个Observable类以及一个Observer接口。

Observer接口:  此接口只定义了一个update方法,当被观察者的状态发生变化时被观察者对象的notifyOeservers()方法会调用这一方法。

  1. public interface Observer {
  2.  
  3. void update(Observable o, Object arg);
  4. }

Observable类:被观察者类都是该类的子类,该类有两个重要的方法:

  setChanged():  设置一个内部标记标记其状态发生变化

  notifyObsers(): 这个方法被调用时会调用所有注册的观察者的update()方法。

  1. package java.util;
  2.  
  3. public class Observable {
  4. private boolean changed = false;
  5. private Vector obs;
  6.  
  7. public Observable() {
  8. obs = new Vector();
  9. }
  10. public synchronized void addObserver(Observer o) {
  11. if (o == null)
  12. throw new NullPointerException();
  13. if (!obs.contains(o)) {
  14. obs.addElement(o);
  15. }
  16. }
  17.  
  18. public synchronized void deleteObserver(Observer o) {
  19. obs.removeElement(o);
  20. }
  21.  
  22. public void notifyObservers() {
  23. notifyObservers(null);
  24. }
  25.  
  26. public void notifyObservers(Object arg) {
  27. Object[] arrLocal;
  28.  
  29. synchronized (this) {
  30. if (!changed)
  31. return;
  32. arrLocal = obs.toArray();
  33. clearChanged();
  34. }
  35.  
  36. for (int i = arrLocal.length-1; i>=0; i--)
  37. ((Observer)arrLocal[i]).update(this, arg);
  38. }
  39.  
  40. public synchronized void deleteObservers() {
  41. obs.removeAllElements();
  42. }
  43.  
  44. protected synchronized void setChanged() {
  45. changed = true;
  46. }
  47.  
  48. protected synchronized void clearChanged() {
  49. changed = false;
  50. }
  51.  
  52. public synchronized boolean hasChanged() {
  53. return changed;
  54. }
  55.  
  56. public synchronized int countObservers() {
  57. return obs.size();
  58. }
  59. }

简单的使用Java对观察者模式的支持:

  1. package cn.qlq.observer;
  2.  
  3. import java.util.Observable;
  4.  
  5. public class Watched extends Observable {
  6.  
  7. private String data = "";
  8.  
  9. public String getData() {
  10. return data;
  11. }
  12.  
  13. public void changeData(String data) {
  14. if (!this.data.equals(data)) {
  15. this.data = data;
  16. setChanged();
  17. }
  18.  
  19. notifyObservers();
  20. }
  21.  
  22. }
  1. package cn.qlq.observer;
  2.  
  3. import java.util.Observable;
  4. import java.util.Observer;
  5.  
  6. public class Watcher implements Observer {
  7.  
  8. @Override
  9. public void update(Observable o, Object arg) {
  10. if (o != null && (o instanceof Watched)) {
  11. Watched watched = (Watched) o;
  12. System.out.println("data changed to: " + watched.getData());
  13. }
  14. }
  15.  
  16. }

客户端代码

  1. package cn.qlq.observer;
  2.  
  3. public class Client {
  4.  
  5. public static void main(String[] args) {
  6. Watched watched = new Watched();
  7. Watcher watcher = new Watcher();
  8.  
  9. watched.addObserver(watcher);
  10.  
  11. watched.changeData("123");
  12. watched.changeData("123");
  13. watched.changeData("456");
  14. watched.changeData("789");
  15. }
  16. }

结果:(虽然改变了四次值,但是有两次一样,查看源码啊在notifyObsers()中会清掉changed的值)

data changed to: 123
data changed to: 456
data changed to: 789

4.  观察者模式优缺点

优点:

(1)观察者模式在被观察者和观察者直接建立一个抽象的耦合

(2)观察者模式支持广播通信。被观察者会向所有登记的观察者发出通知。

缺点:

(1)如果被观察者的观察者过多,通知所有观察者需要花费很多时间

(2)如果在被观察者之间有循环依赖容易循环调用

(3)如果对观察者的通知是通过多线程通知必须保证通知的正确性

(4)观察者可以知道观察者状态发生了变化,不知道是怎么发生变化的。

总结:

意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

如何解决:使用面向对象技术,可以将这种依赖关系弱化。

关键代码:在抽象类里有一个 ArrayList 存放观察者们。

应用实例: 1、拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。 2、西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水招来一个老乌龟,这个乌龟就是观察者,他观察菩萨洒水这个动作。

优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。

缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

注意事项: 1、JAVA 中已经有了对观察者模式的支持类。 2、避免循环引用。 3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。

观察者(Observer)模式的更多相关文章

  1. Java 实现观察者(Observer)模式

    1. Java自带的实现 类图 /** * 观察目标 继承自 java.util.Observable * @author stone * */ public class UpdateObservab ...

  2. 设计模式C++描述----04.观察者(Observer)模式

    一. 概述 Observer 模式要解决的问题为:建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这个“一”的多也能够同步改变. Sbuject 相当于 ...

  3. Java设计模式之从[星际争霸的兵种升级]分析观察者(Observer)模式

    观察者模式定义对象的一种一对多的依赖关系.当一个对象的状态发生改变时.全部依赖于它的对象都会得到通知并被自己主动更新. 一个简单的样例是.在星际争霸的虫族中有一个0基础单位叫做跳狗(Zergling) ...

  4. 面向对象设计模式——观察者(OBSERVER)模式

    定义 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.  Observer模式描述了如何建立这种关系.这一模式中的关键对象是目标(subject ...

  5. 设计模式之观察者(OBSERVER)模式

    定义 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.  Observer模式描述了如何建立这种关系.这一模式中的关键对象是目标(subject ...

  6. java观察者(Observer)模式

    观察者模式:     试想,在电子商务网站上,一个用户看中了一件一份,但是当时衣服的价格太贵,你需要将衣服收藏,以便等衣服降价时自动通知该用户.这里就是典型的观察模式的例子.     1.观察者模式的 ...

  7. Head First 设计模式 —— 02. 观察者 (Observer) 模式

    思考题 在我们的一个实现中,下列哪种说法正确?(多选) P42 public class WeatherDate { // 实例变量声明 public void measurementsChanged ...

  8. 《Head First 设计模式》ch.2 观察者(Observer)模式

    观察者模式 定义了对象之间一对多以来,这样一来,当一个对象改变状态时,它所有的依赖者都会收到通知并自动更新 设计原则-松耦合 松耦合将对象之间的互相依赖降到了最低——只要他们之间的接口仍被遵守 观察者 ...

  9. Observer(观察者)模式

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

随机推荐

  1. bash信号捕捉

    我们ping一个主机,然后按下ctrl+c那么就会终止这个ping动作,如下图: 可是如果使用一个循环来逐个ping不同主机,你再按下ctrl+c就会发现停不下来,直到循环完成,如下图: #!/bin ...

  2. rabbitMq 学习笔记(一)

    消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题 实现高性能,高可用,可伸缩和最终一致性架构. RabbitMQ 是采用 Erlang 语言实现 AMQP (Adva ...

  3. 《JS权威指南学习总结--第7章 数组概念、稀疏数组》

    一.数组概念 数组是值的有序结合.每个值叫做一个元素,而每个元素在数组中都有一个位置,用数字表示,称为索引. JS数组是无类型的:数组元素可以是任意对象,并且同一个数组中的不同元素也可能有不同的类型. ...

  4. B端产品经理的金字塔能力模型

    工作这几年,时长思考,作为B端产品经理自己应该具备什么样的能力? 虽然工作依旧在有条不紊的进行,但是时常会陷入到对知识或者能力的焦虑当中.特别时是工作三五年,产品经理进阶门槛时. 虽然产品经理的能力是 ...

  5. 【MySQL】自增步长调整

    mysql> show variables like '%increment%'; +-----------------------------+-------+ | Variable_name ...

  6. Python从零开始——运算符

  7. Odoo中的env详解

    转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10826382.html 一:environment environment类提供了对ORM对象的封装,同时提 ...

  8. mybatis 模糊查询 mapper.xml的写法

    1. sql中字符串拼接 SELECT * FROM tableName WHERE name LIKE CONCAT(CONCAT('%', #{text}), '%'); 2. 使用 ${...} ...

  9. bloginfo()用法小结|wordpress函数

    bloginfo()显示关于您的wordpress站点的信息,主要是从您的用户配置文件和WordPress管理屏幕的一般设置中收集的信息.它可以在模板文件的任何地方使用.这总是将结果打印到浏览器.如果 ...

  10. 平台级 SAAS 架构的基础:统一身份管理系统

    https://my.oschina.net/bochs/blog/2248954 业内在用户统一身份认证及授权管理领域,主要关注 4 个方面:集中账号管理(Account).集中认证管理(Authe ...