设计模式15---观察者模式(Observer Pattern)
一、观察者模式定义
| 观察者模式定义: |
| Define a one-to-many dependency between objects so that when one object changes state, all its dependents aer notified and updated automatically. |
| 定义对象间一种一对多的依赖关系,使得当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。 |

如上图所示(截取自《Head First Design Patterns》一书),主要包括四个部分:
1. Subject被观察者。是一个接口或者是抽象类,定义被观察者必须实现的职责,它必须能偶动态地增加、取消观察者,管理观察者并通知观察者。
2. Observer观察者。观察者接收到消息后,即进行update更新操作,对接收到的信息进行处理。
3. ConcreteSubject具体的被观察者。定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。
4. ConcreteObserver具体观察者。每个观察者在接收到信息后处理的方式不同,各个观察者有自己的处理逻辑。
二、观察者模式优势
|
观察者和被观察者之间是抽象耦合的,不管是增加观察者还是被观察者都非常容易扩展。 |
| 根据单一职责原则,每个类的职责是单一的,那么怎么把各个单一的职责串联成真实的复杂的逻辑关系呢,观察者模式可以起到桥梁作用。 |
| 观察者模式是松耦合的典型。 |
在Android源码中,其中一个经典的使用到观察者模式的就是Android控件的事件监听模型。
三、观察者模式的实例
1、定义一个抽象被观察者接口

package com.linghu.observer; /***
* 抽象被观察者接口
* 声明了添加、删除、通知观察者方法
* @author linghu
*
*/
public interface Observerable { public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver(); }
2、定义一个抽象观察者接口

package com.linghu.observer; /***
* 抽象观察者
* 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。
* @author linghu
*
*/
public interface Observer {
public void update(String message);
}

3、定义被观察者,实现了Observerable接口,对Observerable接口的三个方法进行了具体实现,同时有一个List集合,用以保存注册的观察者,等需要通知观察者时,遍历该集合即可。

package com.linghu.observer; import java.util.ArrayList;
import java.util.List; /**
* 被观察者,也就是微信公众号服务
* 实现了Observerable接口,对Observerable接口的三个方法进行了具体实现
* @author linghu
*
*/
public class WechatServer implements Observerable { //注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程
private List<Observer> list;
private String message; public WechatServer() {
list = new ArrayList<Observer>();
} @Override
public void registerObserver(Observer o) {
list.add(o);
} @Override
public void removeObserver(Observer o) {
if(!list.isEmpty())
list.remove(o);
} //遍历
@Override
public void notifyObserver() {
for(int i = 0; i < list.size(); i++) {
Observer oserver = list.get(i);
oserver.update(message);
}
} public void setInfomation(String s) {
this.message = s;
System.out.println("微信服务更新消息: " + s);
//消息更新,通知所有观察者
notifyObserver();
} }

4、定义具体观察者,微信公众号的具体观察者为用户User

package com.linghu.observer; /**
* 观察者
* 实现了update方法
* @author linghu
*
*/
public class User implements Observer {
private String name;
private String message; public User(String name) {
this.name = name;
} @Override
public void update(String message) {
this.message = message;
read();
} public void read() {
System.out.println(name + " 收到推送消息: " + message);
} }
5、编写一个测试类
首先注册了三个用户,ZhangSan、LiSi、WangWu。公众号发布了一条消息"PHP是世界上最好用的语言!",三个用户都收到了消息。
用户ZhangSan看到消息后颇为震惊,果断取消订阅,这时公众号又推送了一条消息,此时用户ZhangSan已经收不到消息,其他用户
还是正常能收到推送消息。

package com.linghu.observer;
public class Test {
public static void main(String[] args) {
WechatServer server = new WechatServer();
Observer userZhang = new User("ZhangSan");
Observer userLi = new User("LiSi");
Observer userWang = new User("WangWu");
server.registerObserver(userZhang);
server.registerObserver(userLi);
server.registerObserver(userWang);
server.setInfomation("PHP是世界上最好用的语言!");
System.out.println("----------------------------------------------");
server.removeObserver(userZhang);
server.setInfomation("JAVA是世界上最好用的语言!");
}
}
四、观察者模式在Android源码中的应用
1. 看View类源代码中的OnKeyListener接口:

/**
* Interface definition for a callback to be invoked when a key event is
* dispatched to this view. The callback will be invoked before the key
* event is given to the view.
*/
public interface OnKeyListener {
/**
* Called when a key is dispatched to a view. This allows listeners to
* get a chance to respond before the target view.
*
* @param v The view the key has been dispatched to.
* @param keyCode The code for the physical key that was pressed
* @param event The KeyEvent object containing full information about
* the event.
* @return True if the listener has consumed the event, false otherwise.
*/
boolean onKey(View v, int keyCode, KeyEvent event);
}
2. 再看View类定义了私有成员mOnKeyListener(通过组合的方式):
private OnKeyListener mOnKeyListener;
3. 注册listener

/**
* Register a callback to be invoked when a key is pressed in this view.
* @param l the key listener to attach to this view
*/
public void setOnKeyListener(OnKeyListener l) {
mOnKeyListener = l;
}
4. 剩下的就交给开发者自己构造外部观察者对象与该按键的事件接口进行绑定,获取事件消息。
最后让我们记住支撑“观察者模式”的设计原则: Strive for loosely coupled designs between objects that interact.
设计模式15---观察者模式(Observer Pattern)的更多相关文章
- 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)
原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...
- 二十四种设计模式:观察者模式(Observer Pattern)
观察者模式(Observer Pattern) 介绍定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新. 示例有一个Message实体类,某些对象 ...
- [设计模式] 19 观察者模式 Observer Pattern
在GOF的<设计模式:可复用面向对象软件的基础>一书中对观察者模式是这样说的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.当一个 ...
- c#设计模式之观察者模式(Observer Pattern)
场景出发 一个月高风黑的晚上,突然传来了尖锐的猫叫,宁静被彻底打破,狗开始吠了,大人醒了,婴儿哭了,小偷跑了 这个过程,如果用面向对象语言来描述,简单莫过于下: public class Cat { ...
- 设计模式之观察者模式(Observer pattern)
最近参加了一次面试,其中笔试题有一道编程题,在更换掉试题的描述场景后,大意如下: 上课铃声响起,学生A/B/C/D进入教室:下课铃声响起,学生A/B/C/D离开教室. 要求使用设计模式的思想完成铃与学 ...
- 设计模式九: 观察者模式(Observer Pattern)
简介 观察者属于行为型模式的一种, 又叫发布-订阅模式. 如果一个对象的状态发生改变,依赖他的对象都将发生变化, 那么这种情况就适合使用观察者模式. 它包含两个术语,主题(Subject),观察者(O ...
- 【设计模式】观察者模式 Observer Pattern
定义:观察者模式定义了对象之间的一对多依赖.当“主题”(Object)状态改变事,所有依赖它的“观察者”(Observer)都会受到通知并自动更新.主题支持观察者订阅和退订. 观察者模式提供了一种对象 ...
- 【UE4 设计模式】观察者模式 Observer Pattern
概述 描述 定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新.观察者模式又叫做 发布-订阅(Publish/Subscribe)模式 模型-视图(M ...
- 设计模式-观察者模式(Observer Pattern)
观察者模式(Observer Pattern):定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己. 观察者 ...
- 设计模式 - 观察者模式(Observer Pattern) 详细说明
观察者模式(Observer Pattern) 详细说明 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权全部 ...
随机推荐
- opatch lsinventory –details
今天把RAC的数据库升完级后,在RAC1节点执行opatch lsinventory –detail 命令,没有报错.在rac2节点执行报错: [oracle@rac2 ~]$ opatch lsin ...
- 给深度学习入门者的Python快速教程
给深度学习入门者的Python快速教程 基础篇 numpy和Matplotlib篇 本篇部分代码的下载地址: https://github.com/frombeijingwithlove/dlcv_f ...
- ruby 功力修炼
建表 ActiveRecord::Schema.define do drop_table :hosts if table_exists? :hosts create_table :hosts do | ...
- .net Core 2.0使用NLog
最近研究了一下NLog的使用方式,简单的入了一下门. 实现的功能,对于不同的日志,进行不同的记录,分别有系统运行日志,和个人在程序中写的异常日志.发布之后放在了IIS上.进行查看日志的信息 参考了两篇 ...
- 【冷门】 C# 小技巧之获取变量名称
今天在自我规范程序设计的时候,变量名匹配字符串来自配置文件,网上找了一会儿发现也有朋友在找寻这种方式,很不容易找到一个解决方案来自http://www.th7.cn/Program/net/20140 ...
- 后端生成二维码 - C#生成二维码(QR)
最近在github上找到一个相对比较好的C#二维码生成类库.在这里和大家分享一下. github地址:https://github.com/codebude/QRCoder 把解决方案下载下来,编译生 ...
- 一条跨库更新数据的sql
UPDATE [db1].[dbo].[R_ResAndBook] SET SectionID=TT2.newsecidFROM [SmartCampus].[dbo].[R_ResAndBo ...
- 【总结整理】自带天气app,为什么还要下载
很简单那就说明用户对天气这个功能的需求并没有表面那么简单呗,还有更深层次的需求~ 先声明我自己是没有这方面需求的,我就纯属YY一下 既然数据都一样的话,那是什么让用户觉得天气APP更专业呢? 1.历史 ...
- vim的vim-addons的问题
最近急切想把vim变成IDE,这个过程的毕竟之路就是装插件,vim有自己的插件管理软件装起插件来相当方便,首先安装这个软件: sudo apt-get install vim-addon-manage ...
- spring+springmvc+mybatis+redis 实现两重数据缓存
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http:// ...