定义:

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

结构:(书中图,侵删)

一个抽象的观察者接口,拥有一个更新方法
若干个具体的观察者类
一个抽象的subject类,包含一个抽象观察者的集合,并拥有增加、删除观察者的方法,以及一个通知的方法
若干个具体subject类

实例:

举个看球赛的例子吧。
假设比赛在主场比。
subject就是球赛赛况;具体的subject分为现场看、电视上看。
然后观察者分为主场球迷,客场球迷。
 
抽象观察者接口(球迷接口):
package designpattern.observer;

public interface Fans {
public void react(String result);
}
具体球迷类:
主场球迷:

package designpattern.observer;

public class HomeFans implements Fans {

    @Override
public void react(String result) {
System.out.print("主场球迷:");
if (result.equals("win")) {
System.out.println("Yes! 我们赢啦,主场就是牛批!!!");
} else {
System.out.println("输了,哎...");
}
} }
客场球迷:

package designpattern.observer;

public class AwayFans implements Fans {

    @Override
public void react(String result) {
System.out.print("客场球迷:");
if (result.equals("win")) {
System.out.println("输了,哎...");
} else {
System.out.println("Yes! 客场都赢啦,牛批!!!");
}
} }
抽象subject接口(比赛接口):

package designpattern.observer;

import java.util.ArrayList;
import java.util.List; public interface Match {
List<Fans> fansList = new ArrayList<>();// 这一句 void addFans(Fans fans); void removeFans(Fans fans); void notifyResult(String result); }
注释的那一句说明一下:
书中这句就是写在接口里的,但是写在这里就是一个全局的,所有子类都共用这同一个list
但我自己感觉各个子类所需要通知的观察者应该是不一定一样的,所以我是改到了子类中
但我后来写总结的时候回看定义,发现,总结写的就是“一对多的依赖关系”,既然不是多对多,那自然观察者就是统一调配的
只不过还是感觉有点怪怪的,往集合里添加删除观察者的方法是不是改成静态方法会好一点?
不然,必须要实例化一个子类的对象才能调用。
 
现场看比赛:

package designpattern.observer;

import java.util.ArrayList;
import java.util.List; public class MatchOnTheSpot implements Match {
// List<Fans> fansList = new ArrayList<>(); @Override
public void addFans(Fans fans) {
fansList.add(fans);
} @Override
public void removeFans(Fans fans) {
fansList.remove(fans);
} @Override
public void notifyResult(String result) {
for (Fans fans : fansList) {
fans.react(result);
}
}
}
电视看比赛:

package designpattern.observer;

import java.util.ArrayList;
import java.util.List; public class MatchOnTheTV implements Match {
// List<Fans> fansList = new ArrayList<>(); @Override
public void addFans(Fans fans) {
fansList.add(fans);
} @Override
public void removeFans(Fans fans) {
fansList.remove(fans);
} @Override
public void notifyResult(String result) {
for (Fans fans : fansList) {
fans.react(result);
}
}
}
此例中,两个子类的代码完全相同,可以把接口改成抽象类,然后把方法写到父类中,我这里就不改了。
 
客户端:

package designpattern.observer;

public class Client {
public static void main(String[] args) {
HomeFans homeFans = new HomeFans();
AwayFans awayFans = new AwayFans(); // 现场看
Match match = new MatchOnTheSpot();
match.addFans(homeFans);
match.addFans(awayFans);
System.out.println("主场赢啦~");
match.notifyResult("win"); System.out.println("==========================="); // 电视上看
match = new MatchOnTheTV();
System.out.println("主场输啦~");
match.notifyResult("lose"); }
}
结果输出:
主场赢啦~
主场球迷:Yes! 我们赢啦,主场就是牛批!!!
客场球迷:输了,哎...
===========================
主场输啦~
主场球迷:输了,哎...
客场球迷:Yes! 客场都赢啦,牛批!!!

总结:

(按理说总结才是精华,但我每次总结都不知道要写点什么,可能是理解得还不够深刻吧。)
这个设计模式可以在一个对象改变的同时需要其他对象也跟着改变的时候使用。
好处说来说去就是那么几点,解除了观察者和通知者之间的耦合,将依赖转移给抽象,符合依赖倒转原则。
缺点嘛,就是这里的通知调用的都是同一方法(本例中就是notifyResult()方法),而实际应用中,可能是各种各样的方法名,还有可能有一些是别人已经封装好的方法,根本不可能去继承你的抽象观察者接口。
书中使用了一个叫事件委托的技术来解决这个问题,然后java中并没有直接的封装,实现这个需要用到反射,稍微有点麻烦,我这里就先不实现了,等以后再回来补全。有兴趣的可以自己去试一下。
 

设计模式 | 观察者模式/发布-订阅模式(observer/publish-subscribe)的更多相关文章

  1. RabbitMQ学习第三记:发布/订阅模式(Publish/Subscribe)

    工作队列模式是直接在生产者与消费者里声明好一个队列,这种情况下消息只会对应同类型的消费者. 举个用户注册的列子:用户在注册完后一般都会发送消息通知用户注册成功(失败).如果在一个系统中,用户注册信息有 ...

  2. RabbitMQ指南之三:发布/订阅模式(Publish/Subscribe)

    在上一章中,我们创建了一个工作队列,工作队列模式的设想是每一条消息只会被转发给一个消费者.本章将会讲解完全不一样的场景: 我们会把一个消息转发给多个消费者,这种模式称之为发布-订阅模式. 为了阐述这个 ...

  3. RabbitMQ的发布订阅模式(Publish/Subscribe)

    一.发布/订阅(Publish/Subscribe)模式 发布订阅是我们经常会用到的一种模式,生产者生产消息后,所有订阅者都可以收到.RabbitMQ的发布/订阅模型图如下: 1.该模式下生产者并不是 ...

  4. [转] JavaScript设计模式之发布-订阅模式(观察者模式)-Part1

    <JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...

  5. js设计模式之发布/订阅模式模式

    一.前言 发布订阅模式,基于一个主题/事件通道,希望接收通知的对象(称为subscriber)通过自定义事件订阅主题,被激活事件的对象(称为publisher)通过发布主题事件的方式被通知. 就和用户 ...

  6. js设计模式之发布订阅模式

    1. 定义 发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知. 订阅者(Subscriber)把自己想订阅的事件注册(Subscri ...

  7. C# 委托和事件 与 观察者模式(发布-订阅模式)讲解 by天命

    使用面向对象的思想 用c#控制台代码模拟猫抓老鼠 我们先来分析一下猫抓老鼠的过程 1.猫叫了 2.所有老鼠听到叫声,知道是哪只猫来了 3.老鼠们逃跑,边逃边喊:"xx猫来了,快跑啊!我是老鼠 ...

  8. SpringBoot事件监听机制及观察者模式/发布订阅模式

    目录 本篇要点 什么是观察者模式? 发布订阅模式是什么? Spring事件监听机制概述 SpringBoot事件监听 定义注册事件 注解方式 @EventListener定义监听器 实现Applica ...

  9. javaScript设计模式:发布订阅模式

    发布订阅模式的思想是在观察者模式的基础上演变而来,在观察者模式中客户端监听到对象某个行为就触发对应任务程序.而在发布订阅模式中依然基于这个核心思想,所以有时候也会将两者认为是同一种设计模式.它们的不同 ...

随机推荐

  1. Linux 操作系统基础知识

    1.操作系统总体介绍 •CPU: 就像人的大脑,主要负责相关事情的判断以及实际处理的机制.查询指令: cat /proc/cpuinfo•内存: 大脑中的记忆区块,将皮肤.眼睛等所收集到的信息记录起来 ...

  2. Redis数据结构简介

    Redis可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为STRING(字符串).LIST(列表).SET(集合).HASH(散列)和ZSET(有序集合).有一部分Redis命令对 ...

  3. 那些年,我们追过的RPC

    1974年冬,互联网大师 Jon Postel发表了RFC674:“Procedure Call Protocol Documents,Version 2”,尝试定义一种在包含70个节点的网络中共享资 ...

  4. 嘿嘿嘿,开始自学mysql

    开始学习mysql了,作为非计算机专业学生,必须需要一个地方来给自己的知识进行一些记录和总结. 一SQL语句 数据库是不认识java语言的,但是我们同样要与数据库交互,这时需要使用到数据库认识的语言S ...

  5. 如何查找Linux服务器上JDK安装路径?

    成功远程到你要部署软件的Linux服务器上.这是第一步. 查看JDK版本:java -version 查看java执行路径:which java 查看JAVA_HOME路径:echo $JAVA_HO ...

  6. linux常用命令:创建文件和文件夹

    1.首先说一下touch 创建文件的命令,touch可以用于创建二进制文件,用法非常简单.用法:touch+文件名,touch与文件名之间一定要有空格.图中先用之前分享过的命令来查看一下/目录下面有多 ...

  7. LNMP单点服务器搭建

    一.部署服务器环境 Linux:centos6.5 nginx:1.14.0 mysql:5.6.33 php:5.6.36 1.网络配置 2.FQDN /etc/hosts /etc/sysconf ...

  8. Go的context的问题

    Go的context的问题 2017-05-29 最近被由context引发的一个bug坑得不轻,所以反思一下Go的context的问题. context是隐式的约束,没有检测 如果我们写一个函数,比 ...

  9. 在MFC中通过访问IP地址下载文件到本地

    void CDownLoad::OnBnClickedOk() { // TODO: 在此添加控件通知处理程序代码 CDialogEx::OnOK(); UpdateData(TRUE); CStri ...

  10. BZOJ_3993_[SDOI2015]星际战争_二分+网络流

    BZOJ_3993_[SDOI2015]星际战争_二分+网络流 Description 3333年,在银河系的某星球上,X军团和Y军团正在激烈地作战.在战斗的某一阶段,Y军团一共派遣了N个巨型机器人进 ...