观察者模式
当对象间存在一对多关系时(“多”需要知道“一”的状态或是行为变化),则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。

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

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

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

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

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

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

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

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

使用场景:
1、有多个子类共有的方法,且逻辑相同。
2、重要的、复杂的方法,可以考虑作为模板方法。

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

* 代码实现*
观察者模式使用三个类 Subject、Observer 和 Client。Subject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法。我们创建 Subject 类、Observer 抽象类和扩展了抽象类 Observer 的实体类。
ObserverPatternDemo,我们的演示类使用 Subject 和实体类对象来演示观察者模式。
观察者模式的 UML 图

步骤 1
创建 Subject 类。
Subject.java
import java.util.ArrayList;
import java.util.List;

public class Subject {private List<Observer> observers = new ArrayList<Observer>();private int state;public int getState() {return state;}public void setState(int state) {this.state = state;notifyAllObservers();}public void attach(Observer observer){observers.add(observer);      }public void notifyAllObservers(){for (Observer observer : observers) {observer.update();}}
}

步骤 2

创建 Observer 类。
Observer.java

public abstract class Observer {protected Subject subject;public abstract void update();
}

步骤 3
创建实体观察者类。
BinaryObserver.java

public class BinaryObserver extends Observer{public BinaryObserver(Subject subject){this.subject = subject;this.subject.attach(this);}@Overridepublic void update() {System.out.println( "Binary String: " + Integer.toBinaryString( subject.getState() ) ); }
}

OctalObserver.java

public class OctalObserver extends Observer{public OctalObserver(Subject subject){this.subject = subject;this.subject.attach(this);}@Overridepublic void update() {System.out.println( "Octal String: " + Integer.toOctalString( subject.getState() ) ); }
}

HexaObserver.java

public class HexaObserver extends Observer{public HexaObserver(Subject subject){this.subject = subject;this.subject.attach(this);}@Overridepublic void update() {System.out.println( "Hex String: " + Integer.toHexString( subject.getState() ).toUpperCase() ); }
}

步骤 4

使用 Subject 和实体观察者对象。
ObserverPatternDemo.java
public class ObserverPatternDemo {public static void main(String[] args) {Subject subject = new Subject();new HexaObserver(subject);new OctalObserver(subject);new BinaryObserver(subject);System.out.println("First state change: 15"); subject.setState(15);System.out.println("Second state change: 10");    subject.setState(10);}
}

步骤 5
验证输出。

First state change: 15
Hex String: F
Octal String: 17
Binary String: 1111
Second state change: 10
Hex String: A
Octal String: 12
Binary String: 1010

模拟写个Android的mediaplayer的listener的播放分发吧,注意:只是模拟,建的是Java项目
Media .class(相当于上面的subject) 内部接口PlayingListener相当于上面的Observer 类

public class Media {static Media s_instance = null;// Create Singletonpublic static Media getInstance() {synchronized (Media.class) {if (null == s_instance) {s_instance = new Media();}return s_instance;}}private Media() {}public void play(){//this is just for testsendPlayingMessageActivitis("play one song copelete ");}public interface PlayingListener {public void onMediaPlayNotify(String process);}private final ArrayList<PlayingListener> m_MediaPlayListeners = new ArrayList<PlayingListener>();private void sendPlayingMessageActivitis(String process) {String notifyInfo = process;// this can be objectfor (int i = 0; i < m_MediaPlayListeners.size(); i++) {m_MediaPlayListeners.get(i).onMediaPlayNotify(notifyInfo);}}/* Add listener function */public void addMediaPlayerListener(PlayingListener listener) {synchronized (m_MediaPlayListeners) {// if current listener is nullif (null == listener)return;// if do not contains this listener, add to the memberSDUSBNotifyIDif (!m_MediaPlayListeners.contains(listener)) {m_MediaPlayListeners.add(listener);}}};/* Remove the listener */public void removeMediaPlayerListener(PlayingListener listener) {synchronized (m_MediaPlayListeners) {// if current listener is nullif (null == listener)return;int iIndex = m_MediaPlayListeners.indexOf(listener);if (iIndex >= 0) {m_MediaPlayListeners.remove(iIndex);}}};}

Activities类(相当于上面的各个观察者的实现类)

public class Activity1 {public void Listen() {Media.getInstance().addMediaPlayerListener(new PlayingListener() {@Overridepublic void onMediaPlayNotify(String process) {System.out.println("activity1 listen" + process);}});}
}
public class Activity2 {public void Listen() {Media.getInstance().addMediaPlayerListener(new PlayingListener() {@Overridepublic void onMediaPlayNotify(String process) {System.out.println("activity2 listen" + process);}});}
}
public class Activity3 {public void Listen() {Media.getInstance().addMediaPlayerListener(new PlayingListener() {@Overridepublic void onMediaPlayNotify(String process) {System.out.println("activity3 listen" + process);}});}
}

验证类

public class Client {public static void main(String[] args) {Activity1 a1 = new Activity1();Activity2 a2 = new Activity2();Activity3 a3 = new Activity3();a1.Listen();a2.Listen();a3.Listen();Media.getInstance().play();}
}

验证结果:

activity1 listenplay one song copelete
activity2 listenplay one song copelete
activity3 listenplay one song copelete 

具体分布:

更新 170311

组成部分:

  • 被观察者:

1存储观察者的List
2addListener方法,用于将被观察者添加到List
3notify接口,用于通知观察者变化

  • 观察者抽象类:

被观察者变化时,观察者处理方法(由于观察者可能分多种种类,为了程序结构化,统一实现一个接口)

  • 观察者扩展类:

扩展观察者抽象类,实现被观察者变化时观察者处理的方法。

交互方式:当被观察者发生变化,通过被观察者中存储的观察者的List获取观察者的实例进行交互。

另外:察者扩展类的构造函数中的参数是可省略的,(看案例一)加入这个被观察者对象是有优势的:可以在观察者扩展类的构造函数中直接将被观察者对象传入,并将观察者绑定到被观察者上,这样就不需要被观察者调用接口一次次绑定监听了。

设计模式笔记二十:观察者模式 |更新版相关推荐

  1. 设计模式笔记二十五:访问者模式

    原文:http://www.runoob.com/design-pattern/ 少许个人理解,如有错误请指出.欢迎一起讨论. (本文多摘自原文,对于访问者模式的作用还是有些不是很明白,这篇文章貌似比 ...

  2. 设计模式笔记二十四:模板模式

    原文:http://www.runoob.com/design-pattern/ 少许个人理解,如有错误请指出.欢迎一起讨论(本文大部分转自原文) 在模板模式(Template Pattern)中,一 ...

  3. 设计模式笔记二十二:空对象模式

    原文:http://www.runoob.com/design-pattern/ 少许个人理解,如有错误请指出.欢迎一起讨论. 在空对象模式(Null Object Pattern)中,一个空对象取代 ...

  4. 云计算设计模式(二十四)——仆人键模式

    云计算设计模式(二十四)--仆人键模式 使用一个令牌或密钥,向客户提供受限制的直接訪问特定的资源或服务,以便由应用程序代码卸载数据传输操作. 这个模式是在使用云托管的存储系统或队列的应用中特别实用,而 ...

  5. 云计算设计模式(二十)——调度程序代理管理者模式

    云计算设计模式(二十)--调度程序代理管理者模式 协调一系列在分布式服务集和其它远程资源的的行为,试图透明地处理故障,假设这些操作失败,或撤销,假设系统不能从故障中恢复执行工作的影响.这样的模式能够分 ...

  6. 嵌入式Linux驱动笔记(二十四)------framebuffer之使用spi-tft屏幕(上)

    你好!这里是风筝的博客, 欢迎和我一起交流. 最近入手了一块spi接口的tft彩屏,想着在我的h3板子上使用framebuffer驱动起来. 我们知道: Linux抽象出FrameBuffer这个设备 ...

  7. 模板方法模式 Template method 行为型 设计模式(二十六)

    模板方法模式 Template method 上图为网上百度的一份简历模板截图 相信大家都有求职的经历,那么必然需要简历,写简历的时候,很可能你会网上检索一份简历模板,使用此模板的格式,然后替换为你的 ...

  8. (原创)无废话C#设计模式之二十二:总结(针对GOF23)

    无废话C#设计模式之二十二:总结(针对GOF23) 比较 设计模式 常用程度 适用层次 引入时机 结构复杂度 Abstract Factory 比较常用 应用级 设计时 比较复杂 Builder 一般 ...

  9. Mr.J-- jQuery学习笔记(二十八)--DOM操作方法(添加方法总结)

    Table of Contents appendTo appendTo(source, target) 源代码 append prependTo ​ ​ ​ ​ prependTo源码 prepend ...

最新文章

  1. 全球安全行业融资收购简报(2016年2月)
  2. 主动模式FTP与被动模式FTP该如何选择
  3. 你需要了解的纯原生JS实现带有功能的前端购物车
  4. 有三AI不得不看的几十篇技术综述
  5. 系统上线后关键用户的工作建议
  6. C语言再学习 -- 循环语句
  7. Django目录结构说明
  8. netty系列之:使用POJO替代buf
  9. 流星数据恢复软件 v2.4
  10. 在Linux上将视频转换成动态gif图片 (附:ffmpeg和ImageMagick安装方法)
  11. 数电2_2——逻辑函数的变换与化简
  12. 网络设计与系统集成概述
  13. c#程序设计实训报告心得体会_C#.NET程序设计实验一实验报告
  14. 解决无法看到eth0的简单情况
  15. vmbox设置ubuntu共享文件夹_为什么共享文件夹、打印机访问还是受限?这几个设置解决90%问题...
  16. 不要迷恋我,虽然我利用Python来耍植物大战僵尸,威力加强版
  17. Mangopi MQ-R:T113-s3编译Tina Linux系统(二)SDK目录
  18. 11款Windows必装软件,每一款都非常好用
  19. Ubuntu18.04安装WPS字体缺失的解决方案
  20. 香港十大正规外汇黄金交易平台排名(2021版)

热门文章

  1. 简述python常用的函数模块_Python中常用的Python time模块常用函数
  2. php正则过滤%3e,实用的替换或者过滤数据正则表达式php代码
  3. 【错误】【vscode】'#' not expected here
  4. 《精通并发与Netty》学习笔记(02 - 服务端程序编写)
  5. POJ3321 Apple tree
  6. 002.MEMS应用在开关电源上,实现大功率超小型化
  7. php命名规则几点内容
  8. 比较两个数的大小,自定义比较两个整数的大小的方法
  9. Visual Studio 2008 每日提示(十)
  10. webpack如何将css文件分离的,webpack--css:Less文件的打包和分离(八)