Java 设计模式——观察者模式(Observer Pattern)

image

前言

本来没想写前言的,感觉就是一堆废话。那就当废话浏览一下吧,只是提醒一下自己一些注意的东西。

在许多博客当中看到把观察者模式又称呼为发布-订阅模式。其实我感觉两者确实很相似,但还是有一丢丢的区别:

在发布-订阅模式中消息的发送方,叫做发布者(publishers),消息不会直接发送给特定的接收者(订阅者)。

举个例子:比如微信公众号。意思就是发布者和订阅者不知道对方的存在,需要一个第三方组件,叫做信息中介,它将订阅者和发布者串联起来,它过滤和分配所有输入的消息。(这段从网上找的,大家可以从网上详细了解发布-订阅模式)这里就不跑题了。

image

一、简介

1、属于行为型模式:这些设计模式特别关注对象之间的通信。

2、当对象间存在一对多关系时,则使用观察者模式。比如,当一个对象被修改时,则会自动通知它的依赖对象。

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

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

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

6、使用场景

(1)一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。

(2)一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。

(3)一个对象必须通知其他对象,而并不知道这些对象是谁。

(4)需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

7、注意事项

(1)JAVA 中已经有了对观察者模式的支持类。

(2)避免循环引用。

(3)如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。

image

二、实现步骤

(1)实现方式:

实现观察者模式有很多形式,比较直观的一种是使用一种“注册——通知——注销”的形式。

比如Android中的广播(不懂android也没关系,把它想象成学校的广播就成,具体看下面例子)

观察者模式主要角色

抽象观察者:描述观察者的公共接口(收到消息的方法),也可以定义为接口(interface)。

具体观察者:描述具体观察者并对观察目标的改变做出反应。

抽象被观察者(目标):是指被观察的对象,描述被观察者的公共接口(比如通知、注册、注销等),也可以定义为接口

具体被观察者(具体目标):描述具体的被观察者,与观察者建立联系。当状态发生变化时,通知观察者。

(2)举例:

这里举个例子:智商有点不够用,想不到好的例子,这里就模拟Android四大组件之一的广播实现方式。

首先我们要知道Android广播的大致实现流程:创建接收者(具体观察者)继承广播(抽象观察者),然后注册广播(绑定观察者,建立联系)。广播发送者(具体的被观察者)发送广播通知。最后是注销广播(解除绑定,断开联系)。

看起来有点复杂,换种思路简单的想象成学校发出广播通知学生放学即可。

(3)步骤简化版:

1、创建具体被观察者(学校广播)继承抽象 被观察者

2、创建具体观察者(学生)继承抽象观察者

3、绑定联系

4、发送通知

哈哈 ~!相信到这里大家可以自己手动了实现了,下面贴出具体代码。

image

三、代码实现

抽象 被观察者:Observable.java;具体 被观察者:SchoolsBroadcast.java

/**
 * Observable.java
 *  抽象被观察者
 */
abstract class Observable {
     //发送广播
    abstract void sendBroadcast(String message);
}

/**
 * SchoolsBroadcast.java
 *  具体的 被观察者(学校广播)
 */
public class SchoolsBroadcast extends Observable{
    //用来存储观察者
    private List<Observer> observers = new ArrayList<Observer>();
    @Override
    void sendBroadcast(String message) {
        System.out.println("学校发出通知:"+message);
        for(Observer ob:observers) {
            ob.receive(message);
        }
    }
    //绑定观察者(可以移动到抽象被观察者中)
    public void registerReceiver(Observer observer) {
        observers.add(observer);
    }
    //解绑观察者(可以移动到抽象被观察者中)
    public void unRegisterReceiver(Observer observer) {
        if(observers.contains(observer)) {
            observers.remove(observer);
        }
    }
}
image.gif

抽象 观察者:Observer.java;具体 观察者:StudentA.java、StudentB.java、StudentC.java

/**
 * Observer.java
 *  抽象观察者
 */
abstract class Observer {
    //收到通知
    abstract void receive(String message);
}

/**
 *  StudentA.java
 *  具体的观察者(学生A)
 */
public class StudentA extends Observer{
    @Override
    void receive(String message) {
        System.out.println("学生A收到消息:"+message);
    }
}

/**
 *  StudentB.java
 *  具体的观察者(学生B)
 */
public class StudentB extends Observer{
    @Override
    void receive(String message) {
        System.out.println("学生B收到消息:"+message);
    }
}

/**
 *  StudentC.java
 *  具体的观察者(学生C)
 */
public class StudentC extends Observer{
    @Override
    void receive(String message) {
        System.out.println("学生C收到消息:"+message);
    }
}
image.gif

测试类:Test.java

/**
 * Test.java
 *  测试类
 */
public class Test {
    public static void main(String[] args) {
        //创建被观察者(学校广播)
        SchoolsBroadcast schoolsBroadcast = new SchoolsBroadcast();
        //创建观察者(学生)
        StudentA studentA = new StudentA();
        //绑定观察者 建立联系
        schoolsBroadcast.registerReceiver(studentA);
        schoolsBroadcast.registerReceiver(new StudentB());
        schoolsBroadcast.registerReceiver(new StudentC());
        //被观察者(学校广播)发出通知
        schoolsBroadcast.sendBroadcast("放学");
        System.out.println("=====================");
        //解绑观察者(学生A)
        schoolsBroadcast.unRegisterReceiver(studentA);
        //被观察者(学校广播)发出通知
        schoolsBroadcast.sendBroadcast("学生A请假");
    }
}
image.gif
image

例子很简单、容易忘的可以多写几遍,很容易记住。当然面试时还是贼好用滴!!!

image

四、总结

优点:

1、观察者和被观察者是抽象耦合的。

2、建立一套触发机制。.

3、符合“开闭原则”的要求。

缺点:

1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

五、Demo地址

https://github.com/DayorNight/DesignPattern

六、参考文档

http://www.runoob.com/design-pattern/observer-pattern.html

七、内容推荐

CSDN:https://blog.csdn.net/cs_lwb/article/details/84189465

相关文章:

《JAVA 设计模式——单例模式》

《Java 设计模式——工厂模式》

如果你觉得我写的不错或者对您有所帮助的话。不妨顶一个【微笑】,别忘了点赞、收藏、加关注哈!!

您的每个举动都是对我莫大的支持

image
image

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 设计模式概述 在学习面向对象七大设计原则时需要注意以下几点:a) 高内聚、低耦合和单一职能的“冲突”实际上,这两者...
    彦帧阅读 3,737评论 0 14
  • 1 场景问题# 1.1 订阅报纸的过程## 来考虑实际生活中订阅报纸的过程,这里简单总结了一下,订阅报纸的基本流程...
    七寸知架构阅读 4,601评论 5 57
  • 【学习难度:★★★☆☆,使用频率:★★★★★】直接出处:观察者模式梳理和学习:https://github.com...
    BruceOuyang阅读 1,515评论 1 5
  • 【重庆分公司何梦瑶5月13日分享感悟】 前几天沟通一个青年人,在跟她沟通几度都被堵了回来时,我心里特别的心痛,因为...
    夢瑤阅读 262评论 0 0
  • 清晨五点,当这个城市还在沉睡时,我们已经摸黑起床。六点,外面依然万籁俱寂,我们欢呼雀跃,整装待发。大巴车关掉了所有...
    林夕_ym阅读 867评论 0 3