【设计模式】观察者模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )
【摘要】
文章目录
一、观察者模式简介二、观察者模式适用场景三、观察者模式优缺点四、观察者模式代码示例1、被观察者2、观察者3、通知类4、测试类
五、JDK 中的观察者模式支持类1、Observable...
一、观察者模式简介
观察者模式 : 定义了 对象之间 一对多 的 依赖 , 令 多个 观察者 对象 同时 监听 某一个 主题对象 , 当 主题对象 发生改变时 , 所有的 观察者 都会 收到通知 并更新 ;
观察者 有多个 , 被观察的 主题对象 只有一个 ;
如 : 在购物网站 , 多个用户关注某商品后 , 当商品降价时 , 就会自动通知关注该商品的用户 ;
- 主题对象 : 商品是主题对象 ;
- 观察者 : 用户是观察者 ;
- 观察者注册 : 用户关注 , 相当于注册观察者 ;
- 通知触发条件 : 商品降价 ;
观察者模式 类型 : 行为型 ;
二、观察者模式适用场景
观察者模式适用场景 : 关联行为 场景 , 建立一套 触发机制 ;
如 : 用户关注某个商品的价格 , 降价时进行通知 , 这样 用户 和 商品 产生了关联 , 触发机制就是 商品降价 ,
三、观察者模式优缺点
观察者模式 优点 :
- 抽象耦合 : 在 观察者 和 被观察者 之间 , 建立了一个 抽象的 耦合 ; 由于 耦合 是抽象的 , 可以很容易 扩展 观察者 和 被观察者 ;
- 广播通信 : 观察者模式 支持 广播通信 , 类似于消息广播 , 如果需要接收消息 , 只需要注册一下即可 ;
观察者模式 缺点 :
- 依赖过多 : 观察者 之间 细节依赖 过多 , 会增加 时间消耗 和 程序的复杂程度 ;
这里的 细节依赖 指的是 触发机制 , 触发链条 ; 如果 观察者设置过多 , 每次触发都要花很长时间去处理通知 ; - 循环调用 : 避免 循环调用 , 观察者 与 被观察者 之间 绝对不允许循环依赖 , 否则会触发 二者 之间的循环调用 , 导致系统崩溃 ;
四、观察者模式代码示例
JDK 中提供了观察者模式的支持 ;
- 被观察者 : 被观察者 继承 Observable 类 ;
- 观察者 : 观察者 实现 Observer 接口 ;
- 关联 观察者 与 被观察者 : 调用 被观察者 的 addObserver 方法 , 关联二者 ;
- 触发通知 : 被观察者 数据改变时 , 调用 setChanged 和 notifyObservers 方法 , 会自动回调 观察者的 update 方法 ;
用户在游戏中提出问题 , 管理员负责监听并处理问题 ;
1、被观察者
package observer;
import java.util.Observable;
/**
* 被观察的主题对象
* JDK 提供了对观察者模式的支持 , 被观察者可以继承 Observable 类
*
* 被观察对象 继承 Observable 类
*/
public class Game extends Observable {
private String name;
public Game(String name) {
this.name = name;
}
public String getName() {
return name;
}
/**
* 用户提交问题
* @param game
* @param question
*/
public void produceQuestion(Game game, Question question) {
System.out.println(question.getUserName() +
" 在 " + game.name + " 游戏中提交问题 : " + question.getContent());
// 该方法是 Observable 提供的方法
// 将 private boolean changed = false 成员变量设置为 true
// 代表 被观察者 的状态发生了改变
setChanged();
// 通知 观察者
notifyObservers(question);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
2、观察者
package observer;
import java.util.Observable;
import java.util.Observer;
/**
* 管理员类
* 管理员类观察的是游戏
* 用户反馈的问题 属于 游戏 , 管理员关注的是游戏
* 无法关注 问题
*
* 如 : 在电商平台 , 关注的是某个商品 , 在降价时发送通知
* 商品是存在的 , 降价消息 在关注的时候还没有被创建 , 是无法获取依赖的
*/
public class Manager implements Observer {
/**
* 管理员名称
*/
private String name;
public Manager(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
// 获取 被观察者 对象
Game game = (Game) o;
// 获取 被观察者 对象 调用 notifyObservers 方法的参数
Question question = (Question) arg;
System.out.println(name + " 观察者 接收到 被观察者 " + game.getName() +
" 的通知 , 用户 " + question.getUserName() +
" 提出问题 " + question.getContent());
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
3、通知类
package observer;
public class Question {
/**
* 用户名
*/
private String userName;
/**
* 问题内容
*/
private String content;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
4、测试类
package observer;
public class Main {
public static void main(String[] args) {
// 创建被观察者
Game game = new Game("Cat And Mouse");
// 创建观察者
Manager manager = new Manager("Tom");
// 关联 观察者 与 被观察者
game.addObserver(manager);
// 业务逻辑 : 用户提出问题到游戏中 , 管理员接收到通知消息
Question question = new Question();
question.setUserName("Jerry");
question.setContent("游戏崩溃");
// 在游戏中提交问题
game.produceQuestion(game, question);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
执行结果 :
Jerry 在 Cat And Mouse 游戏中提交问题 : 游戏崩溃
Tom 观察者 接收到 被观察者 Cat And Mouse 的通知 , 用户 Jerry 提出问题 游戏崩溃
- 1
- 2
五、JDK 中的观察者模式支持类
1、Observable
被观察者需要继承该类 ;
public class Observable {
private boolean changed = false;
/** 使用 Vector 是线程安全的集合 , 存放观察者对象 , 在构造器中初始化该类 */
private Vector<Observer> obs;
/** Construct an Observable with zero Observers. */
public Observable() {
obs = new Vector<>();
}
/**
* 添加观察者对象 , 采用了 synchronized 修饰 , 是同步方法 , 保证了线程安全
*
* @param o an observer to be added.
* @throws NullPointerException if the parameter o is null.
*/
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
/**
* 删除观察者
*/
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
/**
* 通知观察者 , 无参
*
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers() {
notifyObservers(null);
}
/**
* 通知观察者 , 有参
*
* @param arg any object.
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
/**
* 查看观察者数量
*
* @return the number of observers of this object.
*/
public synchronized int countObservers() {
return obs.size();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
2、Observer
观察者需要实现该接口 ;
package java.util;
/**
* A class can implement the <code>Observer</code> interface when it
* wants to be informed of changes in observable objects.
*
* @author Chris Warth
* @see java.util.Observable
* @since JDK1.0
*/
public interface Observer {
/**
* 当 被观察者 对象发生改变时 , 即被观察者对象调用 notifyObservers 方法时 , 自动调用该方法
*
* @param o 被观察的对象.
* @param arg 被观察对象调用 notifyObservers 方法时传入的参数
*/
void update(Observable o, Object arg);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
文章来源: hanshuliang.blog.csdn.net,作者:韩曙亮,版权归原作者所有,如需转载,请联系作者。
原文链接:hanshuliang.blog.csdn.net/article/details/119748365
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)