Java设计模式中的观察者模式
作者:非凡的小笨鱼 发布时间:2021-08-22 01:27:20
标签:Java,观察者模式,设计模式
一.介绍
观察者模式(Observer Pattern)属于行为型模式。定义了对象之间的一对多依赖,让多个观察者同时监听某一个主题对象,类似于广播机制,只需要分发广播,感兴趣的对象自动接收该广播。我们平常所说的Observer、Listener、Hook、Callback都和这个模式有关
二.场景约束
小孩(Baby)哭的时候会通知到爸爸(Dad)和妈妈(Mum),爸爸妈妈会对此采取不同的行为
三.UML类图
版本一
版本二
新增事件类将观察者与主题解耦,观察者可以根据不同的事件执行不同的操作,也可以直接对事件源进行操作
四.示意代码(版本一)
业务代码
//抽象观察者
public interface Observer {
void action();
}
//抽象主题
abstract class Subject{
protected List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public abstract void notifyObserver();
}
//具体主题-被观察者
class Baby extends Subject{
@Override
public void notifyObserver() {
System.out.println("baby cry");
observers.forEach(Observer::action);
}
}
//具体观察者
class Dad implements Observer {
@Override
public void action() {
System.out.println("dad feed baby");
}
}
//具体观察者
class Mum implements Observer {
@Override
public void action() {
System.out.println("mum hug baby");
}
}
客户端
public class Client {
public static void main(String[] args) {
Baby baby = new Baby();
baby.addObserver(new Mum());
baby.addObserver(new Dad());
baby.notifyObserver();
}
}
五.示意代码(版本二)
//抽象观察者
public interface Observer {
void action(Event event);
}
//抽象主题
abstract class Subject {
protected List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public abstract void notifyObserver();
}
//具体主题-被观察者
class Baby extends Subject {
@Override
public void notifyObserver() {
System.out.println("baby cry");
CryEvent cryEvent = new CryEvent(new Date().getTime(), this);
observers.forEach(observer -> observer.action(cryEvent));
}
}
//抽象事件
abstract class Event {
public abstract Object getSource();
}
//具体事件
class CryEvent extends Event {
public long when;
Baby source;
public CryEvent(long when, Baby source) {
this.when = when;
this.source = source;
}
@Override
public Baby getSource() {
return source;
}
}
//具体观察者
class Dad implements Observer {
@Override
public void action(Event event) {
System.out.println("dad feed baby");
if(event.getSource() instanceof Baby){
System.out.println("dad对事件源进行处理");
}
}
}
//具体观察者
class Mum implements Observer {
@Override
public void action(Event event) {
System.out.println("mum hug baby");
if(event.getSource() instanceof Baby){
System.out.println("mum对事件源进行处理");
}
}
}
客户端
public class Client {
public static void main(String[] args) {
Baby baby = new Baby();
baby.addObserver(new Dad());
baby.addObserver(new Mum());
baby.notifyObserver();
}
}
六.观察者模式与发布订阅模式
发布订阅模式
发布者不会直接通知订阅者
发布者与订阅者完全解耦
观察者模式
主题要自己通知(notify)观察者
主题与观察者松耦合
七.优点
符合依赖倒置原则(观察者与主题都依赖于抽象)
降低耦合(主题与观察者之间的耦合关系)
八.在JDK中的典型应用
在java.awt包下有很多观察者模式的身影,先来看下简单的UML类图
主题角色:java提供的组件类(以Button为例) 观察者角色:java提供的事件监听(各种Listener) 事件角色:鼠标事件、键盘事件等等
再来看看一个小demo 在窗口中添加一个按钮,给按钮添加上鼠标与键盘的相关事件,当点击按钮或者按下键盘的时候在控制台打印相应的语句
public class MainFrame extends JFrame {
public MainFrame() throws HeadlessException {
//定义一个具体主题
Button button = new Button("click");
//给主题添加观察者(鼠标监听)
button.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
//MouseEvent就是具体事件
System.out.println("按钮被点击");
}
});
//给主题添加观察者(键盘监听)
button.addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
//KeyEvent就是具体事件
System.out.println("按下" + e.getKeyChar());
}
});
add(button);
setSize(100,100);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public static void main(String[] args) {
new MainFrame();
}
}
这里的KeyAdapter与MouseAdapter使用的是适配器模式
来源:https://blog.csdn.net/a347635191/article/details/122393104
0
投稿
猜你喜欢
- 拆分实现流程请看下面这张图首先我们得对线程池进行一个功能拆分Thread Pool 就是我们的线程池,t1,t2,t3代表三个线程Block
- 问题在使用 Abp 框架的后台作业时,当后台作业抛出异常,会导致整个程序崩溃。在 Abp 框架的底层执行后台作业的时候,有 try/catc
- 1、conditional注解介绍含义: 基于条件的注解作用: 根据是否满足某一个特定条件来决定是否创建某个特定的bean意义: Sprin
- 一、栈1.1 概述Java为什么要有集合类: 临时存储数据。链表的本质: 对象间通过持有和引用关系互相关联起来。线性表: 普通线性表, 操作
- 最近一个项目中,需要用到Java的websocket新特性,于是就学了一下,感觉这技术还挺好玩的,瞬间知道网页上面的那些在线客服是怎么做的了
- java使用stream实现list中对象属性的合并:根据两个List中的某个相同字段合并成一条List,包含两个List中的字段一、前言为
- springboot配置文件中属性变量引用@@这种属性应用方式是field_name=@field_value@。两个@符号是springb
- 使用ehcache-spring-annotations使得在工程中简单配置即可使用缓存下载地址:http://code.google.co
- 前言上一篇我们介绍了使用 sqflite 这个数据库工具在 Flutter 的应用中建立本地数据库的实例应用。了解过数据库的同学应该会知道,
- 本文实例为大家分享了java图形用户界面实现菜单功能的具体代码,供大家参考,具体内容如下题目:编写一个图形用户界面,实现菜单的功能。有3个一
- 定义:封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。类型:行为类模式类图:例子:例如
- 本文实例讲解了iOS从背景图中取色的代码,分享给大家供大家参考,具体内容如下实现代码:void *bitmapData; //内存空间的指针
- 前言这里主要简单介绍如何使用Camera+SurfaceView自定义相机拍照,如果是Camera2或者是TextureView的可以前往主
- mybatis insert foreach循环插入@Insert("<script>" +
- throw抛出异常的方式比较直接:if(age < 0){throw new MyException("年龄不能为负数!&q
- 一、实战-内存溢出堆内存溢出栈内存溢出方法区溢出直接内存溢出二、实战-堆内存溢出演示堆内存溢出代码,并且定位问题总结堆内存溢出的场景与解决方
- 目录为什么要实现调用链跟踪?如何实现?第一步,看图、看场景,用户浏览器的一次请求行为所走的路径是什么样的第二步,实现。不想看代码可直接拉最后
- 前言:线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、
- 一、添加依赖<!--SpringBoot使用Swagger2构建API文档的依赖--> <dep
- 一、常见游戏规则从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要