单一职责原则(设计模式)
目录
问题:
定义:
解决:
方式 1:使用策略模式
示例:用户管理
方式 2:使用装饰者模式
示例:用户操作
方式 3:使用责任链模式
示例:用户操作链
总结
推荐
问题:
今天刷面经的时候,发现不理解单一职责原则,特此记录。
定义:
单一职责原则:一个模块或类只完成一个功能。
那可以想一想,引起类变化的原因有哪些呢?
总结下来,只有2种
- 添加
- 修改
如果我们可以,将“添加”和“修改”分开,那么这个类也就完成了单一职责原则
建议先了解一下 委托者模式,因为下面几个设计模式核心都是委托者模式。
解决:
在 Java 开发中,如果你想 将“引起一个类的变更的原因”进行拆分,通常需要遵循单一职责原则,让修改(Modify)和添加(Add)两个操作独立,不相互影响。
可以用 策略模式、装饰者模式、责任链模式、组合模式 等方式来实现。下面是几种常见的方式:
方式 1:使用策略模式
如果修改和添加是两种不同的操作,可以用策略模式拆分,让它们各自处理自己的逻辑。
示例:用户管理
// 定义通用策略接口
public interface UserOperationStrategy {void execute(User user);
}// 修改策略
public class ModifyUserStrategy implements UserOperationStrategy {@Overridepublic void execute(User user) {System.out.println("修改用户信息: " + user.getName());}
}// 添加策略
public class AddUserStrategy implements UserOperationStrategy {@Overridepublic void execute(User user) {System.out.println("添加新用户: " + user.getName());}
}// 上下文类,动态选择操作
public class UserService {private UserOperationStrategy strategy;public void setStrategy(UserOperationStrategy strategy) {this.strategy = strategy;}public void executeOperation(User user) {strategy.execute(user);}
}// 使用策略
public class Main {public static void main(String[] args) {User user = new User("Tom");UserService userService = new UserService();// 进行添加操作userService.setStrategy(new AddUserStrategy());userService.executeOperation(user);// 进行修改操作userService.setStrategy(new ModifyUserStrategy());userService.executeOperation(user);}
}
优点:
- 让“修改”和“添加”逻辑完全解耦,互不影响。
- 方便扩展,比如再加一个“删除用户”策略。
方式 2:使用装饰者模式
如果修改和添加可以叠加,可以使用装饰者模式,在原功能基础上动态增加额外行为,而不改变原类的代码。
示例:用户操作
// 定义基础接口
public interface UserOperation {void execute();
}// 基础实现(原始功能)
public class BaseUserOperation implements UserOperation {@Overridepublic void execute() {System.out.println("基础用户操作");}
}// 装饰器基类
public abstract class UserOperationDecorator implements UserOperation {protected UserOperation decoratedOperation;public UserOperationDecorator(UserOperation decoratedOperation) {this.decoratedOperation = decoratedOperation;}@Overridepublic void execute() {decoratedOperation.execute();}
}// 添加用户功能
public class AddUserDecorator extends UserOperationDecorator {public AddUserDecorator(UserOperation decoratedOperation) {super(decoratedOperation);}@Overridepublic void execute() {super.execute();System.out.println("添加用户");}
}// 修改用户功能
public class ModifyUserDecorator extends UserOperationDecorator {public ModifyUserDecorator(UserOperation decoratedOperation) {super(decoratedOperation);}@Overridepublic void execute() {super.execute();System.out.println("修改用户");}
}// 使用装饰器
public class Main {public static void main(String[] args) {UserOperation operation = new BaseUserOperation();// 先添加,再修改UserOperation addThenModify = new ModifyUserDecorator(new AddUserDecorator(operation));addThenModify.execute();}
}
输出
基础用户操作
添加用户
修改用户
优点
- 动态组合行为,比如 先添加再修改 或者 只修改不添加。
- 方便扩展,不用修改原类。
方式 3:使用责任链模式
如果修改和添加是流程中的不同步骤,可以用责任链模式,让不同操作按顺序执行,方便扩展。
示例:用户操作链
// 责任链接口
public interface UserHandler {void handle(User user);
}// 责任链基类
public abstract class AbstractUserHandler implements UserHandler {protected UserHandler nextHandler;public void setNextHandler(UserHandler nextHandler) {this.nextHandler = nextHandler;}@Overridepublic void handle(User user) {if (nextHandler != null) {nextHandler.handle(user);}}
}// 添加用户处理器
public class AddUserHandler extends AbstractUserHandler {@Overridepublic void handle(User user) {System.out.println("添加用户: " + user.getName());super.handle(user);}
}// 修改用户处理器
public class ModifyUserHandler extends AbstractUserHandler {@Overridepublic void handle(User user) {System.out.println("修改用户信息: " + user.getName());super.handle(user);}
}// 流程控制
public class Main {public static void main(String[] args) {User user = new User("Tom");// 责任链AddUserHandler addHandler = new AddUserHandler();ModifyUserHandler modifyHandler = new ModifyUserHandler();addHandler.setNextHandler(modifyHandler);// 先添加,再修改addHandler.handle(user);}
}
输出
添加用户: Tom
修改用户信息: Tom
总结
方案 | 适用场景 | 主要特点 |
---|---|---|
策略模式 | 修改和添加是两种独立操作 | 通过不同策略切换操作,逻辑清晰,便于扩展 |
装饰者模式 | 需要叠加功能,比如先添加再修改 | 允许动态组合多个操作,避免修改原类 |
责任链模式 | 操作有固定顺序,比如先添加再修改 | 让多个处理器按顺序执行,扩展性强 |
推荐
- 如果“修改”和“添加”是两种完全独立的操作,用 策略模式。
- 如果“修改”和“添加”可能会动态组合,用 装饰者模式。
- 如果“修改”和“添加”是必须按固定顺序执行,用 责任链模式。
相关文章:
单一职责原则(设计模式)
目录 问题: 定义: 解决: 方式 1:使用策略模式 示例:用户管理 方式 2:使用装饰者模式 示例:用户操作 方式 3:使用责任链模式 示例:用户操作链 总结 推荐 问题&a…...
生理信号概念
rPPG 信号(远程光电容积脉搏波信号) 原理: 基于光电容积脉搏波描记法,利用普通摄像头,在一定距离外捕捉人体皮肤表面因心脏泵血导致的血液容积变化引起的细微颜色变化,通过图像处理和信号分析算法提取心率…...

安卓内存泄露之DMA-BUF异常增长:Android Studio镜像引起DMA内存泄露
安卓内存泄露之DMA-BUF异常增长:Android Studio镜像引起DMA内存泄露 - Wesley’s Blog 今天用着安卓 14 的板子的时候突然系统卡死。 查看日志发现launcher都被干掉了 03-04 06:13:35.544 7872 8479 I ActivityManager: vis BFGS 18740: com.android.launcher3 (pid 8407) se…...
android13打基础: 控件checkbox
测试checkbox的activity // todo: 高级控件checkbox public class Ch4_CheckBoxActivity extends AppCompatActivityimplements CompoundButton.OnCheckedChangeListener {Overrideprotected void onCreate(Nullable Bundle savedInstanceState) {super.onCreate(savedInstance…...
AI应用测试:遇到类ChatGPT的流式接口要如何压测?
先说结论: 使用最普遍的JMeter 就能支持类 OpenAI 的流式接口(如 ChatGPT 的流式聊天接口)的测试 总体设置 JMeter 支持测试 OpenAI 的流式接口,但需要额外配置(如启用 KeepAlive 和调整超时)。如果需要实时处理流式响应,使用 Regular Expression Extractor 或自定义脚…...
React面试葵花宝典之二
36.Fiber的更新机制 React Fiber 更新机制详解 React Fiber 是 React 16 引入的核心架构重构,旨在解决可中断渲染和优先级调度问题,提升复杂应用的流畅性。其核心思想是将渲染过程拆分为可控制的工作单元,实现更细粒度的任务管理。以下是其…...

在日常生活、工作中deepseek能帮我们解决哪些问题
在日常生活、工作中deepseek能帮我们解决哪些问题 DeepSeek极大降低了普通人使用AI的门槛,让AI快速渗透到人们的工作和生活中,无论是专业场景提效、教育学术赋能、商业创新甚至日常生活,都变得更加轻松。 当然这篇文章也参考了deepseek的回…...
【Java】IO流
Java IO流是Java中处理输入输出的核心机制,通过不同的流类型实现了对数据的高效读写。 一、IO流的分类 1. 按数据方向 输入流(Input Stream):从数据源(如文件、网络等)读取数据。输出流(Outp…...

HTML第三节
一.初识CSS 1.CSS定义 A.内部样式表 B.外部样式表 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title&g…...

Visual Studio 2022安装问题解决,提示无法安装Microsoft.VisualStudio.Community.Msi
表现现象为:安装完后提示无法安装Microsoft.VisualStudio.Community.Msi,无法正常开发C项目 查看日志,大概显示: xxx ReturnCode1316 xxxxx 消息详细信息: 指定的帐户已存在。 试了网上所有的办法都没用,反复尝试&…...
【代码分享】基于IRM和RRT*的无人机路径规划方法详解与Matlab实现
基于IRM和RRT*的无人机路径规划方法详解与Matlab实现 1. IRM与RRT*的概述及优势 IRM(Influence Region Map)通过建模障碍物的影响区域,量化环境中的安全风险,为RRT算法提供启发式引导。RRT(Rapidly-exploring Random…...

MybatisPlus从入门到精通
一、MyBatis-Plus核心特性 无侵入性 在MyBatis基础上增强,无需修改原有代码即可使用。自动化CRUD 内置通用Mapper和Service,减少80%单表操作代码。Lambda表达式 支持Lambda形式的条件构造,避免字段名硬编码错误。主键策略 支持雪花算法&…...
el-table input textarea 文本域 自适应高度,切换分页滚动失效处理办法
场景: el-table 表格 需要 input类型是 textarea 高度是自适应,第一页数据都是单行数据 不会产生滚动条,但是第二页数据是多行数据 会产生滚动条, bug: 第一页切换到第二页 第二页滚动条无法展示 解决办法:直接修改样…...

基于Windows11的DockerDesktop安装和布署方法简介
基于Windows11的DockerDesktop安装和布署方法简介 一、下载安装Docker docker 下载地址 https://www.docker.com/ Download Docker Desktop 选择Download for Winodws AMD64下载Docker Desktop Installer.exe 双点击 Docker Desktop Installer.exe 进行安装 测试Docker安装是…...

ffmpeg源码编译支持cuda
1.安装cuda CUDA Toolkit 11.3 Downloads | NVIDIA Developer 在选择组件的时候,将CUDA中的Nsight VSE和Visual Studio Integration取消勾选 不然会安装失败 2.编译ffmpeg 把cuda编译宏定义开启,再编译avcodec 3.编译livavutil报错struct "Cuda…...

动漫短剧开发公司,短剧小程序搭建快速上线
在当今快节奏的生活里,人们的娱乐方式愈发多元,而动漫短剧作为新兴娱乐形式,正以独特魅力迅速崛起,成为娱乐市场的耀眼新星。近年来,动漫短剧市场呈爆发式增长,吸引众多创作者与观众目光。 从市场规模来看…...
《2025软件测试工程师面试》接口测试篇
基础概念 什么是接口测试? 接口测试是测试系统组件间接口的一种测试,主要用于检测外部系统和内部系统之间以及各个子系统之间的交互点。测试的重点是检查数据的交换、传递和控制管理的过程,以及系统间的相互逻辑依赖关系等。 接口测试的优势是什么? 接口测试具有规范性与扩…...
嵌入式学习第二十三天--网络及TCP
进程通信的方式: 同一主机 传统 system V 不同主机 网络 --- 解决不同主机间 的进程间通信 网络 (通信) //1.物理层面 --- 联通(通路) //卫星 2G 3G 4G 5G 星链 (千帆) //2.逻辑层面 --- 通路(软件) MAC os LINUX …...

Elasticsearch:解锁深度匹配,运用Elasticsearch DSL构建闪电般的高效模糊搜索体验
目录 Elasticsearch查询分类 叶子查询 全文检索查询 match查询 multi_match查询 精确查询 term查询 range查询 复杂查询 bool查询简单应用 bool查询实现排序和分页 bool查询实现高亮 场景分析 问题思考 解决方案 search_after方案(推荐) point in time方案 方案…...

SQLAlchemy系列教程:基本数据类型及自定义类型
在SQLAlchemy、Python SQL工具包和ORM中定义模型时,理解基本数据类型至关重要。本教程提供了在SQLAlchemy模型中有效使用内置基本类型的指南。 SQLAlchemy中的基本类型 SQLAlchemy支持一组与SQL数据库类型一致的基本数据类型。SQLAlchemy中的每种类型都为各种SQL类…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...

Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...