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


猜你喜欢
- *res/raw和assets的相同点:1.两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制。*res/raw和as
- 最近要做一个网站,要求实现验证码程序,经过不断调试,终于成功实现功能。一、验证码生成类生成验证码的话需要用到java的Graphics类库,
- 本文实例为大家分享了Unity排行榜优化滚动效果的具体代码,供大家参考,具体内容如下自己做的一个优化排行榜的功能,当有大量的数据需要在scr
- 数据传输在Android开发过程中,我们常常通过Intent在各个组件之间传递数据。例如在使用startActivity(android.c
- 一:前言最近老师布置了给多级菜单的作业,感觉蛮有意思的,可以提升自己的逻辑!下面我写个简易版的多级菜单,本人还是菜鸟,欢迎各位给予宝贵的建议
- 一、管理网络状态使用网络进行数据通信前,需要先获取网络状态。使用ConnectivityManager获取网络状态步骤:1.获取Connec
- 模板编程是idea的强大功能,也提高了开发人员的编程效率,比如输入main函数:public static void main(String
- 1、打开代码管理器2、打开后就可以看到如下图所示3、复制粘贴该路径,转到该文件夹下新加一个txt文件,把下面的文本复制粘贴<?xml
- [LeetCode] 3. Longest Substring Without Repeating Characters 最长无重复字符的子
- 缘起工作时使用java开发服务器后台,用Jersey写Restful接口,发现有一个Post方法始终获取不到参数,查了半天,发现时获取参数的
- 使用Java实现图像分割,供大家参考,具体内容如下为减少动画制作过程中的IO操作,我们可以使用连续动画来改善动画播放效率。假如我们有如下的一
- 1.Quartz是什么?Quartz是一个开源的Java调度框架,可以用来实现在指定的时间或时间间隔触发任务执行的功能。它支持多种方式的作业
- SpringCloud Gateway 简介SpringCloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基
- String对象是不可变的:意思就是无论是对String的新增或修改,出现一个全新的String内容时,都意味着诞生了一个新的对象。但是如果
- spring中事务处理原理 利用aop生成代理对象执行带有Transactional事务注解的
- using System;using System.Collections.Generic;using System.ComponentMo
- 前言:在java的网络通信中,两个不同节点的主机想要进行通信则可以通过建立Socket对象(相当于客户端主机,向服务端请求发送信息)和Ser
- 前言关于ThreadLocal (线程本地存储),从字面意思上看主要是存储一些本地变量,使它们能在一个线程内共用,与其他的线程进行数据隔离,
- Java8新特性系列我们已经介绍了Stream、Lambda表达式、DateTime日期时间处理,最后以“NullPointerExcept
- 使用IDEA配置Maven搭建开发框架ssm教程一、配置Maven环境1.下载Maven:下载链接2.下载完成解压压缩包并创建本地仓库文件夹