观察者模式【Observer Pattern】,什么是观察者模式?作用?优缺点?观察者模式实现?

观察者模式【Observer Pattern】,什么是观察者模式?作用?优缺点?观察者模式实现?

目录

设计模式专栏目录(点击进入…)

观察者模式【Observer Pattern】,什么是观察者模式?作用?优缺点?观察者模式实现?

目录什么是观察者模式?观察者模式作用?观察者模式优缺点优点缺点

观察者模式包含角色(1)抽象主题 (Subject)(2)具体主题 (Concrete Subject)(3)抽象观察者 (Observer)(4)具体观察者 (Concrete Observer)

观察者模式实现方式观察者模式实现1、实现Observable(被观察者)2、实现Observer(李斯、王斯、刘斯)3、Client(使用观察者)

什么是观察者模式?

​ 观察者模式 (Observer Pattern) 又叫发布-订阅模式 (Publish/Subscribe),是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。

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

观察者模式的核心是将观察者与主题对象解耦,以类似于消息、广播发送的机制联动两者,使被观察者的变动能通知到感兴趣的观察者们,从而做出相应的响应。

观察者模式作用?

创建了对象间的一种一对多的依赖关系,当一个对象状态改变时,所有依赖于它的对象都会得到通知并自动更新。

观察者模式优缺点

优点

抽象耦合:观察者和主题之间是抽象耦合的。 触发机制:建立了一套状态改变时的触发和通知机制。

缺点

性能问题:如果观察者众多,通知过程可能耗时。 循环依赖:可能导致循环调用和系统崩溃。 缺乏变化详情:观察者不知道主题如何变化,只知道变化发生。

观察者模式包含角色

(1)抽象主题 (Subject)

指被观察的对象 (Observable)。该角色是一个抽象类或接口,定义了增加、删除、通知观察者对象的方法

(2)具体主题 (Concrete Subject)

具体被观察者,当其内部状态变化时,会通知已注册的观察者

(3)抽象观察者 (Observer)

定义了响应通知的更新方法

(4)具体观察者 (Concrete Observer)

在得到状态更新时,会自动做出响应

主题(Subject):也称为被观察者或可观察者,它是具有状态的对象,并维护着一个观察者列表。主题提供了添加、删除和通知观察者的方法。 观察者(Observer):观察者是接收主题通知的对象。观察者需要实现一个更新方法,当收到主题的通知时,调用该方法进行更新操作。 具体主题(Concrete Subject):具体主题是主题的具体实现类。它维护着观察者列表,并在状态发生改变时通知观察者。 具体观察者(Concrete Observer):具体观察者是观察者的具体实现类。它实现了更新方法,定义了在收到主题通知时需要执行的具体操作。

观察者模式实现方式

(1)定义观察者接口:包含一个更新方法。 (2)创建具体观察者:实现观察者接口,定义接收到通知时的行为。 (3)定义主题接口:包含添加、删除和通知观察者的方法。 (4)创建具体主题:实现主题接口,管理观察者列表,并在状态改变时通知它们。

观察者模式实现

《孙子兵法》有云:“知彼知己,百战不殆;不知彼而知己,一胜一负;不 知彼,不知己,每战必殆”,

那怎么才能知己知彼呢? 知己是很容易的,自己的军队嘛,很容易知道。

那怎么知彼呢? 安插间谍是很好的一个办法。 韩非子大家都应该记得吧,法家的代表人物,主张建立法制社会,实施重罚制度,真是非常有远见呀,看看现在社会在呼吁什么,建立法制化的社会,在 2000 多年前就已经提出了。大家可能还不知道,法家还有一个非常重要的代表人物,李斯,对,就是李斯,秦国的丞相,最终被残忍的车裂的那位,李斯和韩非子都是荀子的学生,李斯是师兄,韩非子是师弟,若干年后,李斯成为最强诸侯秦国的上尉,致力于统一全国,于是安插了间谍到各个国家的重要人物的身边,以获取必要的信息,韩非子作为韩国的重量级人物,身边自然没少间谍了,韩非子早饭吃的什么,中午放了几个 P,晚上在做什么娱乐,李斯都了如指掌,那可是相隔千里!怎么做到的呢?间谍呀!

1、实现Observable(被观察者)

JDK 中提供了 :java.util.Observable 实现类和 java.util.Observer 接口。

package com.uhhe.common.design.observer;

import java.util.Observable;

/**

* 韩非子,李斯的师弟,韩国的重要人物

*

* @author nizhihao

* @version 1.0.0

* @date 2023/3/1 17:06

*/

public class HanFeiZi extends Observable {

/**

* 韩非子要吃饭了

*/

public void haveBreakfast() {

System.out.println("韩非子:开始吃饭了...");

// 通知所有的观察者

super.setChanged();

this.notifyObservers("韩非子在吃饭");

}

/**

* 韩非子开始娱乐了,古代人没啥娱乐,你能想到的就那么多

*/

public void haveFun() {

System.out.println("韩非子:开始娱乐了...");

super.setChanged();

this.notifyObservers("韩非子在娱乐");

}

}

2、实现Observer(李斯、王斯、刘斯)

李斯

package com.uhhe.common.design.observer;

import java.util.Observable;

import java.util.Observer;

/**

* 李斯这个人,是个观察者,只要韩非子一有动静,这边就知道

*

* @author nizhihao

* @version 1.0.0

* @date 2023/3/1 17:09

*/

public class LiSi implements Observer {

/**

* 首先李斯是个观察者,一旦韩非子有活动,他就知道,他就要向老板汇报

*

* @param observable 观察者

* @param obj 报告内容

*/

@Override

public void update(Observable observable, Object obj) {

System.out.println("李斯:观察到李斯活动,开始向老板汇报了...");

this.reportToQiShiHuang(obj.toString());

System.out.println("李斯:汇报完毕,秦老板赏给他两个萝卜吃吃...\n");

}

/**

* 汇报给秦始皇

*

* @param reportContext 报告内容

*/

private void reportToQiShiHuang(String reportContext) {

System.out.println("李斯:报告,秦老板!韩非子有活动了--->" + reportContext);

}

}

刘斯

package com.uhhe.common.design.observer;

import java.util.Observable;

import java.util.Observer;

/**

* 刘斯这个人,是个观察者,只要韩非子一有动静,这边就知道

*

* @author nizhihao

* @version 1.0.0

* @date 2023/3/1 17:11

*/

public class LiuSi implements Observer {

@Override

public void update(Observable observable, Object obj) {

//刘斯,观察到韩非子活动后,自己也做一定得事情

System.out.println("刘斯:观察到韩非子活动,开始动作了...");

this.happy(obj.toString());

System.out.println("刘斯:真被乐死了\n");

}

private void happy(String context) {

//一看韩非子有变化,他就快乐

System.out.println("刘斯:因为" + context + ",——所以我快乐呀!");

}

}

王斯

package com.uhhe.common.design.observer;

import java.util.Observable;

import java.util.Observer;

/**

* 王斯,也是观察者,杜撰的人名

*

* @author nizhihao

* @version 1.0.0

* @date 2023/3/1 17:11

*/

public class WangSi implements Observer {

@Override

public void update(Observable observable, Object obj) {

// 王斯,看到韩非子有活动,自己就受不了

System.out.println("王斯:观察到韩非子活动,自己也开始活动了...");

this.cry(obj.toString());

System.out.println("王斯:真真的哭死了...\n");

}

private void cry(String context) {

// 一看李斯有活动,就哭,痛哭

System.out.println("王斯:因为" + context + ",——所以我悲伤呀!");

}

}

3、Client(使用观察者)

package com.uhhe.common.design.observer;

import java.util.Observer;

/**

* 使用观察者

*

* @author nizhihao

* @version 1.0.0

* @date 2023/3/1 17:04

*/

public class Client {

/**

* 观察者模式【Observer Pattern】

* 观察者模式有一个变种叫做发布/订阅模型(Publish/Subscribe)

*

* 观察者模式在实际项目的应用中非常常见

* 比如: 到 ATM 机器上取钱,多次输错密码,卡就会被 ATM 吞掉,吞卡动作发生的时候,会触发哪些事件呢?

* 第一,摄像头连续快拍

* 第二,通知监控系统,吞卡发生;

* 第三,初始化 ATM 机屏幕,返回最初状态

* 不能因为就吞了一张卡,整个 ATM 都不能用了吧,一般前两个动作都是通过观察者模式来完成的

*

* 广播链的问题?

* 如果你做过数据库的触发器,你就应该知道有一个触发器链的问题,比如表 A 上写了一个触发器,

* 内容是一个字段更新后更新表 B 的一条数据,而表 B 上也有个触发器,要更新表 C,表 C 也有

* 触发器…,完蛋了,这个数据库基本上就毁掉了!我们的观察者模式也是一样的问题,一个观察者可以有双

* 重身份,即使观察者,也是被观察者,这没什么问题呀,但是链一旦建立,这个逻辑就比较复杂,可维护

* 性非常差,根据经验建议,在一个观察者模式中最多出现一个对象既是观察者也是被观察者,也就是说消

* 息最多转发一次(传递两次),这还是比较好控制的

*

* 异步处理问题?

* 这个 EJB 是一个非常好的例子,被观察者发生动作了,观察者要做出回应,如果观察者比较多,

* 而且处理时间比较长怎么办?那就用异步呗,异步处理就要考虑线程安全和队列的问题,这个

* 大家有时间看看 Message Queue,就会有更深的了解。

*

* 工厂方法模式的时候用到了 ClassUtils 这个类,其中有一个方法就是根据接口查找到所有的实现类,问题解决了吧!

* 可以查找到所有的观察者,然后全部加进来,以后要是新增加观察者也没有问题呀,程序那真是一点都不用改了

*/

public static void main(String[] args) {

// 三个观察者产生出来

Observer liSi = new LiSi();

Observer wangSi = new WangSi();

Observer liuSi = new LiuSi();

// 定义出韩非子

HanFeiZi hanFeiZi = new HanFeiZi();

// 后人根据历史,描述这个场景,有三个人在观察韩非子

hanFeiZi.addObserver(liSi);

hanFeiZi.addObserver(wangSi);

hanFeiZi.addObserver(liuSi);

// 然后这里我们看看韩非子在干什么

hanFeiZi.haveBreakfast();

}

}

← 上一篇: 手机QQ广场功能在哪进入?QQ广场玩法介绍
下一篇: 身体有癌,耳朵先知?耳朵出现一个症状,可能是癌症前兆 →

相关推荐