基于策略模式企业实战中策略命中设计
背景
在公司实际项目项目开发中,有一个策略命中的开发需求。根据用户请求参数的不同来动态返回不同的业务数据。比如说有城市、客户年龄、请求时间3个策略维度,不同的城市返回不同的地区的地标,根据时间地标的背景色要发生变化等等的需求。当然,如果你直接使用一堆的嵌套if/else来硬代码编写这个业务的话,确实也行。那难度再升级一下,有20个策略维度的话,这代码谁维护谁跑路。
所以我们要用合理规范的设计模式来实现该功能。
方案拟定
先来了解一下策略模式的概念:
策略模式是一种设计模式,它定义了一系列算法,并将每个算法封装起来,使他们可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
在Java中,可以使用如下步骤实现策略模式:
- 定义策略接口,该接口定义了所有算法的公共接口。
- 实现策略接口,为每种算法实现一个具体策略类。
- 创建一个上下文类,该类持有一个策略类的引用,并且实现策略接口的方法。
- 客户端代码中,创建一个上下文对象,并设置一个具体策略对象。
策略模式的意义在于:
- 可以让算法和业务代码分离,使得算法可以独立演化,不会影响业务代码。
- 可以在不修改业务代码的情况下更换算法,提高了系统的灵活性。
- 可以很容易地扩展新的算法,而不需要修改原有的代码。
- 可以减少代码的冗长,使代码更加清晰易读。
简单来说的话,就是创建一个接口,该接口定义一个公共的方法,实现类继承这个接口,实现具体的功能。再创建一个service类,对外提供服务时是通过这个类去动态传入实际处理逻辑的实现类去完成任务。
需求分析
结合实际业务场景来设计代码演练一下,拿上面的需求来开发。案例中我们来实现城市、客户年龄、请求时间3个策略维度的命中功能判断服务。
功能刨析:
- 需要一个定义了策略接口
IStrategy
,接口中有执行策略判断方法executeStrategy()
; - 城市策略
CityStrategy
、客户年龄AgeStrategy
、请求时间策略RquestTimeStrategy
都实现IStrategy
接口 - 策略实现类
StrategyService
是对外实现策略命中的类
大局来看主要是这3部分,细节我们在下面的章节来补充。
策略模式架构代码实现
准备工作
- 封装请求报文中的策略类
@Data
public class RequestStrategyInfo {private String cityInfo;private String ageInfo;private String requestTime;....
}
1. 定义策略统一接口
public interface IStrategy {boolean executeStrategy();
}
2. 各个策略实现IStrategy
接口
城市策略
public class CityStrategy implements IStrategy {@Overridepublic boolean executeStrategy() {}
}
年龄策略
public class AgeStrategy implements IStrategy {@Overridepublic boolean executeStrategy() {}
}
请求时间策略
public class RquestTimeStrategy implements IStrategy {@Overridepublic boolean executeStrategy() {}
}
3. StrategyService
对外提供策略匹配服务
StrategyService是最重要的,在这个类里,它要识别出当前判断的策略需要调用哪个具体的策略实例来执行,这有好几种方法:
- 策略工厂
import java.lang.reflect.InvocationTargetException;public class StrategyFactory {@Overridepublic IStrategy createStrategy(String strategyType) {try {Class<?> strategyClass = Class.forName(strategyType);return (IStrategy) strategyClass.getDeclaredConstructor().newInstance();} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {e.printStackTrace();}return null;}
}
public class StrategyService {private IStrategy strategy;private StrategyFactory strategyFactory;public boolean executeStrategy() {// 是否支持任意策略if (strategyInfo.getIsAll()) {return true;}// 获取从数据库详细的策略信息StrategyItem si = strategyItemService.qryStrategyItem(itemId);String strategyType = si.getStrategyType();// 根据strategyType获得对应的策略实例strategy = strategyFactory.createStrategy(strategyType);// 执行策略匹配规则return strategy.executeStrategy();}
}
这种方法可以完成动态找到需要的实现类,不过要求strategyType与类名有强关联关系,必须要通过strategyType来创建实例,也可通过定义枚举类来进一步解耦。
- 在上面的基础上定义枚举类
StrategyEnum
进行解耦
public enum StrategyType {CityStrategy("city", CityStrategy.class),AgeStrategy("age", AgeStrategy.class),RequestTimeStrategy("requestTime", RequestTimeStrategy.class);private String strategyType;private Class<? extends IStrategy> strategyClass;SortType(String sortType, Class<? extends IStrategy> strategyClass) {this.strategyType = strategyType;this.strategyClass = strategyClass;}public Class<? extends IStrategy> getStrategyClassBySortType(String strategyType) {StrategyType[] values = StrategyType.values();return Arrays.stream(values).filter(it -> it.strategyType.equals(strategyType)).findFirst().get().strategyClass;}
}
StrategyService需要稍微改造
public class StrategyService {private IStrategy strategy;private StrategyFactory strategyFactory;public boolean executeStrategy() {// 是否支持任意策略if (strategyInfo.getIsAll()) {return true;}// 获取从数据库详细的策略信息StrategyItem si = strategyItemService.qryStrategyItem(itemId);String strategyType = si.getStrategyType();// 根据strategyType获得对应的策略实例// strategy = strategyFactory.createStrategy(strategyType);try {strategy = StrategyType.getStrategyClassBySortType(strategyType).newInstance();} catch (InstantiationException | IllegalAccessException e) {e.printStackTrace();}// 执行策略匹配规则return strategy.executeStrategy();}
}
使用枚举可以解耦strategyType和策略类名的关系,在枚举里面维护对应关系,以后如果有新的策略,直接添加枚举即可。
- 如果第二种方法不喜欢的话,可以通过在StrategyService中定义一个Map集合维护strategyType与类名的关系
public class StrategyService {private Map<String, Class<? extends IStrategy>> strategyMap;public StrategyService() {strategyMap = new HashMap<>();strategyMap.put("city", CityStrategy.class);strategyMap.put("age", AgeStrategy.class);strategyMap.put("requestTime", RequestTimeStrategy.class);}private IStrategy strategy;private StrategyFactory strategyFactory;public boolean executeStrategy() {// 是否支持任意策略if (strategyInfo.getIsAll()) {return true;}// 获取从数据库详细的策略信息StrategyItem si = strategyItemService.qryStrategyItem(itemId);String strategyType = si.getStrategyType();// 根据strategyType获得对应的策略实例// strategy = strategyFactory.createStrategy(strategyType);/*try {strategy = StrategyType.getStrategyClassBySortType(strategyType).newInstance();} catch (InstantiationException | IllegalAccessException e) {e.printStackTrace();}*/Class<? extends IStrategy> strategyClass = strategyMap.get(strategyType);if (Class<? extends IStrategy> strategyClass = strategyMap.get(strategyType);== null) {throw new IllegalArgumentException("Unsupported strategy type: " + strategyType);}try {strategy = strategyClass.getDeclaredConstructor().newInstance();} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {e.printStackTrace();}// 执行策略匹配规则return strategy.executeStrategy();}
}
用Map维护映射的话,需要考虑策略的数量,如果数量巨大的话,对性能开销可不容小看的;而且这种映射关系手动维护在类里面的做法,可能不太优雅。
- 如果你觉得上述3种方法的硬代码、耦合度都达不到你公司的标准,你可以选择程序在初始化时动态加载全部 IStrategy 接口下的实现类实例到ArrayList中的方式
在自动选择策略时,会遍历一遍所有的策略是否支持当前操作策略类型。在选择使用这种方式前,需要对IStrategy接口进行改造:
public interface IStrategy {boolean executeStrategy();// 当前实现类是否支持boolean support(String strategyType);
}
实现类中对support()方法进行完善,举个例子,比如城市策略:
public class CityStrategy implements IStrategy {@Overridepublic boolean executeStrategy() {}@Overridepublic boolean support(String strategyType) {return "CityStrategy".equals(strategyType);}
}
其余策略方式一致,可考虑将字符串定义成常量在IStrategy接口中,这样会更规范一点
在StrategyService中使用时,需要在初始化时先将IStrategy接口下的所有实现类放到ArrayList中,提供给executeStrategy()方法使用
public class StrategyService implements InitializingBean {@Autowiredprivate ApplicationContext appContext;private Collection<IStrategy> strategys;private IStrategy strategy;private StrategyFactory strategyFactory;public boolean executeStrategy() {// 是否支持任意策略if (strategyInfo.getIsAll()) {return true;}// 获取从数据库详细的策略信息StrategyItem si = strategyItemService.qryStrategyItem(itemId);String strategyType = si.getStrategyType();// 根据strategyType获得对应的策略实例IStrategy strategy = strategys.parallelStream().filter(it -> it.support(strategyType)).findFirst().get();// 执行策略匹配规则return strategy.executeStrategy();}@Overridepublic void afterPropertiesSet() throws Exception() {Map<String, IStrategy> strategyMap = appContext.getBeansOfType(IStrategy.class);strategys = strategyMap.values();}
}
这种方法不需要保证strategyType和策略类名的一一对应关系,是解耦最为激进的一种方式。但是如果策略数量非常多,遍历整个列表可能带来性能问题。
没有最好的方法,只有最适合的方法。如果策略数量不多,那么使用Map来存储映射关系是一个好的选择。如果策略数量非常多,而且不需要频繁地添加和移除策略,那么使用抽象的策略工厂是一个不错的选择。如果策略数量非常多,进一步考虑一定的解耦性,可添加枚举类解耦。如果对解耦的需求更重要于性能考虑,可考虑使用ArrayList遍历的方法。
业务绑定策略设计与代码实现
上一章节只讲述了策略模式架构的设计与不同场景选择策略实例的方式,这一章相当于上一章节的前传。要先有业务绑定了策略之后,请求业务才有策略匹配。
【根据用户请求参数的不同来动态返回不同的业务数据。】这个业务的场景是有一个管理后台,去设定某个业务绑定某些策略。当客户端带着请求参数来访问该业务时,我们要对请求参数的某些字段的值与该业务选择的策略值进行一一比较,若全都符合时,方可返回该业务数据。
实体类设计
城市、年龄、时间等这些定义为策略类型,城市中包含广州、上海、北京、深圳,年龄有18、19、20这些定义为策略值。
策略类型实体类为StrategyType
@Data
public class StrategyType {private Long id; // 主键private String type; // 类型private String name; // 类型名称private String oper; // 支持的操作
}
策略值实体类为StrategyValue
public class StrategyValue {private Long id; // 主键private Long typeId; // 策略类型idprivate String value; // 策略值
}
单单有策略类型与其具体的策略值是不够的,业务如何绑定策略?我们假设操作上是这样的一个流程:在创建好一个业务之后,选择关联策略,城市选择广州,年龄选择等于(大于、小于)18,点击保存。捋一下这两者的关系不难发现,业务与策略值之间是多对多的关系。数据库层面还需要要建一个关联表。
关键字段有:业务id、策略值id、操作类型
操作类型有:等于、大于、小于、不等于;
这个思路去做可以实现灵活度非常高的策略配置,但缺点就是如果每个业务都需要配置多个策略,尤其是一些策略几乎每个都要配置的,那每次都要进行相同的多次操作确实很烦人。
在这里我给出的优化建议有两个,第一个是保存历史操作记录,业务添加策略时读取操作记录表的数据,操作记录保存多少条这个看具体情况而定;第二个是新增一个复合策略表,可以组合一些常用的复合策略,比如广州市18岁策略,在选择策略时可以选择复合策略。
业务绑定策略并没有什么复杂操作,代码主要与业务代码镶嵌,不方便举例。查找出业务绑定的策略时,封装成一个对象。
@Data
public class StrategyDetail {private Long id;private String type;private String oper;private String value;
}
策略匹配设计
这一章节讲述客户端传入策略与数据库中的策略匹配的设计。你可以理解成,这一章节将重点讲述IStrategy接口中的executeStrategy()的实现。
有些同学可能就认为,就这有什么难的,我在每个策略实现类中都用业务策略.equals(请求参数)
不就无敌了?如果说只有【等于】这么一种操作类型确实可以这么做,但我们有多种操作类型,不能在每个策略实现类都写一遍重复性的代码。
封装一个策略匹配工具
public class StrategyUtil {// 匹配public static boolean matchStrategy(RequestStrategyInfo requestInfo, StrategyDetail detail) {Object reqVal = null;try {reqVal = getReqVal(requestInfo, detail.getType());}return computeOper(detail.getOper(), detail.getValue(), reqVal);}// 获取请求对象中的值private Object getReqVal(RequestStrategyInfo requestInfo, String type) {// 利用反射来获取请求对象中的值,但要求策略类型的值要与RequestStrategyInfo类的属性同名Field f = RequestStrategyInfo.class.getDeclareField(type);f.setAccessible(true);return f.get(requestInfo);}// 对比值private boolean computeOper(String oper, String value, Object val) {boolean result = false;switch (oper) {case "0":result = value.equals(val);break;case "1": // 小于result = Double.parseDouble(val) < Double.parseDouble(value);break;case "2": // 大于result = Double.parseDouble(val) > Double.parseDouble(value);break;case "3":result = !value.equals(val);break;}return result;}
}
我们来举个城市策略的调用例子
public class CityStrategy implements IStrategy {@Overridepublic boolean executeStrategy(RequestStrategyInfo requestInfo, StrategyDetail detail) {boolean result = StrategyUtil.matchStrategy(requestInfo, detail);// 若有特殊处理操作可在此加上return result;}
}
几乎所有的策略实现类都是这样的一行代码,如果有特殊操作可以补充在后面。
与前面的选择策略实现类相结合
public class StrategyService implements InitializingBean {@Autowiredprivate ApplicationContext appContext;private Collection<IStrategy> strategys;private IStrategy strategy;private StrategyFactory strategyFactory;// 由业务类自己提供所有的策略详情public boolean executeStrategy(List<strategyDetails> strategyDetails) {// 是否支持任意策略,没有策略则说明支持所有字段if (strategyDetails.size() == 0 || strategyDetails == null) {return true;}List<Boolean> matchList = new ArrayList<>();for (StrategyDetail sd : strategyDetails) {boolean b = strategys.parallelStream().filter(it -> it.support(sd.type)).findFirst().get().executeStrategy(requestInfo, sd);matchList.add(b);}boolean b = matchList.stream().filter(it -> it == false).findFirst().orElse(null);return b == null ? true : false;}@Overridepublic void afterPropertiesSet() throws Exception() {Map<String, IStrategy> strategyMap = appContext.getBeansOfType(IStrategy.class);strategys = strategyMap.values();}
}
在业务实现类的实现思路
public class XxxServiceImpl {@Autowiredprivate StrategyService strategyServicepublic void xxx() {// 1. 处理业务......// 2. 根据业务id找出全部的关联策略详情List<StrategyDetail> strategyDetails = xxxx.getByServiceId(xx);boolean support = strategyService.executeStrategy(strategyDetails);if (support) {// 支持则进行的操作} else {// 不支持的操作}......}
}
总结
基于策略模式设计的策略命中设计,主要难点是策略模式的框架设计理念与策略值对比。
相关文章:
基于策略模式企业实战中策略命中设计
背景 在公司实际项目项目开发中,有一个策略命中的开发需求。根据用户请求参数的不同来动态返回不同的业务数据。比如说有城市、客户年龄、请求时间3个策略维度,不同的城市返回不同的地区的地标,根据时间地标的背景色要发生变化等等的需求。当…...
pod生命周期,pod控制器service
一:pod-demo.yml apiVersion: v1 # <string> kind: Pod # <string> metadata: # <Object>对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字…...
SAP FICO 深入讲解会计凭证
SAP系统在数据处理,无论是业务处理,还是财务处理都会产生大量的凭证,无论是什么凭证,最终的反映形式就是 会计凭证。 1.凭证原则Code 每笔记账都一直以凭证形式存储,每一凭证都作为前后一致的单位保留在系统中…...
LeetCode 2341. 数组能形成多少数对
【LetMeFly】2341.数组能形成多少数对 力扣题目链接:https://leetcode.cn/problems/maximum-number-of-pairs-in-array/ 给你一个下标从 0 开始的整数数组 nums 。在一步操作中,你可以执行以下步骤: 从 nums 选出 两个 相等的 整数从 nums…...
PHPStorm常用快捷键
alt 1 左侧项目结构树隐藏或者显示,这两个组合键的使用可以切换“项目结构树”和当前打开文件之间的焦点。 alt 2 隐藏或者显示 Favorites Ctrl Shift F12 切换到最大编辑器窗口,隐藏其他所有的工具窗口。例如项目结构树、Favorites、Terminal等。…...

【基于腾讯云的远程机械臂小车】
【基于腾讯云的远程机械臂小车】1. 项目来源1.1 项目概述1.2 系统结构1.3 设计原理2. 硬件搭建2.1 CH32V307开发板2.2 Arduino mega25602.3 富斯I6遥控器2.4 机械臂小车2.5 ESP8266 MCU2.5.1 ESP8266 MCU介绍2.5.2 腾讯云固件烧录3. 软件设计3.1 两种控制方式3.1.1 富斯I6遥控机…...

兼职任务平台收集(一)分享给有需要的朋友们
互联网时代,给人们带来了很大的便利。信息交流、生活缴费、足不出户购物、便捷出行、线上医疗、线上教育等等很多。可以说,网络的时代会一直存在着。很多人也在互联网上赚到了第一桶金,这跟他们的努力和付出是息息相关的。所谓一份耕耘&#…...
MarkDown中公式的编辑
MarkDown中公式的编辑生成目录积分插入编号常见希腊字母大小写分式括号求和积分连乘根式三角函数运算符集合运算箭头逻辑运算符约等于向量绝对值申明: 未经许可,禁止以任何形式转载,若要引用,请标注链接地址。 全文共计1077字&…...

解决jupyter以及windows系统中pycharm编译器画图的中文乱码问题大全
一、jupyter环境下中文乱码问题解决 我们在jupyter的notebook中使用matplotlib画图的时候,经常性的会遇见一些中文乱码显示□的情况,如下所示: 在此,网上给出的方法大多是以下的解决方法: import matplotlib.pyplot as pltplt.rcParams[fo…...

06 OpenCV 阈值处理、自适应处理与ostu方法
1 基本概念 CV2中使用阈值的作用是将灰度图像二值化,即将灰度图像的像素值根据一个设定的阈值分成黑白两部分。阈值处理可以用于图像分割、去除噪声、增强图像对比度等多个领域。例如,在物体检测和跟踪中,可以通过对图像进行阈值处理来提取目…...

RFC7519规范-JWT - json web token
简介 什么是JWT(JSON Web Token) 在介绍JWT之前,我们先来回顾一下利用token进行用户身份验证的流程: 客户端使用用户名和密码请求登录服务端收到请求,验证用户名和密码验证成功后,服务端会签发一个token,再把这个to…...

移动机器人设计与实践课程大纲
MiR移动机器人参考资料:图一 西北工业大学-课程平台图二 清华大学出版社-移动机器人目前,基本都是双一流大学开设此类课程,并且都是至少3-4学分,16学时/学分,48-64学时。(⊙﹏⊙),难办了。咱这只有…...

Lesson 7.2 Mini Batch K-Means与DBSCAN密度聚类
文章目录一、Mini Batch K-Means 算法原理与实现二、DBSCAN 密度聚类基本原理与实践1. K-Means 聚类算法的算法特性2. DBSCAN 密度聚类基本原理3. DBSCAN 密度聚类的 sklearn 实现除了 K-Means 快速聚类意外,还有两种常用的聚类算法。(1) 是能…...
11.Dockerfile最佳实践
Dockerfile 最佳实践 Docker官方关于Dockerfile最佳实践原文链接地址:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ Docker 可以通过从 Dockerfile 包含所有命令的文本文件中读取指令自动构建镜像,以便构建给定镜像。 …...

【企业云端全栈开发实践-1】项目介绍及环境准备、Spring Boot快速上手
本节目录一、 项目内容介绍二、Maven介绍2.1 Maven作用2.2 Maven依赖2.3 本地仓库配置三、Spring Boot快速上手3.1 Spring Boot特点3.2 遇到的Bug:spring-boot-maven-plugin3.3 遇到的Bug2:找不到Getmapping四、开发环境热部署一、 项目内容介绍 本课程…...

5-HT2A靶向药物|适应症|市场销售-上市药品前景分析
据世界卫生组织称,抑郁症是一种多因素疾病,影响全球约3.5 亿人。中枢神经系统最广泛的单胺 - 血清素 (5-HT) 被认为在这种情况的病理机制中起着至关重要的作用,并且神经递质的重要性被“血清素假说”提升,将抑郁症的存在联系起来 …...

HTTPS协议原理---详解
目录 一、HTTPS 1.加密与解密 2.我们为什么要加密? 3.常见加密方式 ①对称加密 ②非对称加密 4.数据摘要 5.数字签名 二、HTTPS的加密方案 1.只是用对称加密 2.只使用非对称加密 3.双方都使用非对称加密 4.非对称加密+对称加密 中间人攻…...

Pytest学习笔记
Pytest学习笔记 1、介绍 1.1、单元测试 单元测试是指在软件开发当中,针对软件的最小单位(函数,方法)进行正确性的检查测试 1.2、单元测试框架 测试发现:从多个py文件里面去找到我们测试用例测试执行:按…...

Fuzz概述
文章目录AFL一些概念插桩与覆盖率边和块覆盖率afl自实现劫持汇编器clang内置覆盖率反馈与引导变异遗传算法fork server机制AFL调试准备AFL一些概念 插桩与覆盖率 边和块 首先,要明白边和块的定义 正方形的就是块,箭头表示边,边表示程序执行…...

区块链知识系列 - 系统学习EVM(四)-zkEVM
区块链知识系列 - 系统学习EVM(一) 区块链知识系列 - 系统学习EVM(二) 区块链知识系列 - 系统学习EVM(三) 今天我们来聊聊 zkEVM、EVM 兼容性 和 Rollup 是什么? 1. 什么是 Rollup rollup顾名思义,就是把一堆交易卷(rollup)起来…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...