当前位置: 首页 > news >正文

设计模式学习笔记 - 项目实战三:设计实现一个支持自定义规则的灰度发布组件(实现)

概述

上两篇文章,我们讲解了灰度组件的需求和设计的思路。不管之前讲的限流、幂等框架,还是现在讲的灰度组件,功能性需求都不复杂,相反,非功能性需求是开发的重点。

本章,按照上篇文章的灰度组件的设计思路,讲解如何进行编码实现。不过,本章对实现的讲解,前前面两个实战项目有所不同。在前两个项目中,我们都是手把手从最基础的 MVP 代码将其。然后讲解如何 review 代码发现问题、重构代码解决问题,最终得到一份高质量的代码。考虑到前面两个项目的学习锻炼,你应该对开发套路、思考路径已经很熟悉了,所以,本章就不从最基础的将其了,而是重点讲解实现思路。


灰度组件功能需求整理

针对上连篇文章的开发需求和设计思路,我们还是按照老套路,从中剥离出 V1 版本要实现的内容。为了方便讲解,我把灰度组件的开发需求和设计思路,重新整理罗列了一下,放到了这里。

1.灰度规则的格式和存储方式

支持不同格式(JSON、YAML、XML 等)、不同存储方式(本地配置我呢间、Redis、Zookeeper、或者自研配置中心)的灰度规则配置方式。实际上,这一点和之前的限流框架中限流规则的格式和存储方式完全一致,代码实现也是相同的。所以这个就不重复了,你可以回头去看《限流框架(实现)》章节内容。

2.灰度组件的语法格式

我们支持三种灰度规则语法格式:具体值(比如 893)、区间值(比如 1020-1120)、比例值(比如 %30)。此外,对于更加复杂的灰度规则,比如只对 30 天内购买过某某商品并且退款次数少于 10 次的用户进行更改,我们通过编程的方式来实现。

3.灰度规则的内存组织方式

类似于限流框架中的限流规则,我们需要把灰度规则组织成支持快速查询的数据结构能够快速判定某个灰度对象(darkTarget,比如用户 ID),是否落在灰度规则设定的范围内。

4.灰度规则热更新

修改了灰度规则之后,我们不希望重新部署和重启系统,新的灰度规则就能生效,所以,我们需要支持灰度规则热更新。

在 V1 版本中,对于第一点灰度规则的合适和存储方式,我们只支持 YAML 格式本地文件的配置存储方式。对于剩下的三点,我们都要进行实现。考虑到 V1 版本要实现的内容比较多,我们分两步来实现代码,第一步先讲大的流程、框架搭建好,第二步再进一步添加、丰富、优化功能。

实现灰度组件基本功能

// 目录结构
com.example.darklaunch--DarkLaunch (框架的最顶层入口类)--DarkFeature (每个feature的灰度规则)--DarkRule (灰度规则)--DarkRuleConfig (用来映射配置到内存中)// Demo示例
public class Demo {public static void main(String[] args) {DarkLaunch darkLaunch = new DarkLaunch();DarkFeature darkFeature = darkLaunch.getDarkFeature("call_newapi_getUserById");System.out.println(darkFeature.enabled());System.out.println(darkFeature.dark(893));}
}// 灰度规则配置(dark-rule.yaml)放在classpath路径下
features:
- key: call_newapi_getUserByIdenabled: truerule: {893,342,1020-1120,%30}
- key: call_newapi_registerUserenabled: truerule: {1391198723, %10}
- key: newlog_loanenabled: truerule: {0-1000}

从 Demo 代码中,可以看出,对于业务系统来说,灰度组件的两个直接使用的类是 DarkLaunchDarkFeature

我们先来看 DarkLaunch 类。这个类是灰度组件最顶层入口类。它用来组装其他类对象,串联整个操作流程,提供外部调用的接口。

DarkLaunch 类先读取灰度规则配置文件,映射为内存中的 Java 对象(DarkRuleConfig),然后再将这个中间结构,构建成一个支持快速查询的数据结构(DarkRule)。此外,它还负责定期更新灰度规则,也就是前面提到的灰度热更新。

为了避免更新规则和查询规则并发冲突,在更新灰度时,我们并非直接操作老的 DarkRule,而是先创建一个新的 DarkRule,然后等新的 DarkRule 都构建好之后,再 “瞬间” 赋值给老的 DarkRule

public class DarkLaunch {private static final Logger log = LoggerFactory.getLogger(DarkLaunch.class);private static final int DEFAULT_RULE_UPDATE_TIME_INTERVAL = 60; // in secondsprivate DarkRule rule;private ScheduledExecutorService executor;public DarkLaunch(int ruleUpdateTimeInterval) {loadRule();this.executor = Executors.newSingleThreadScheduledExecutor();this.executor.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {loadRule();}}, ruleUpdateTimeInterval, ruleUpdateTimeInterval, TimeUnit.SECONDS);}public DarkLaunch() {this(DEFAULT_RULE_UPDATE_TIME_INTERVAL);}private void loadRule() {// 将灰度规则配置文件dark-rule.yaml中的内容读取到DarkRuleConfig中InputStream in = null;DarkRuleConfig ruleConfig = null;try {in = this.getClass().getResourceAsStream("dark-rule.yaml");if (in != null) {Yaml yaml = new Yaml();ruleConfig = yaml.loadAs(in, DarkRuleConfig.class);}} finally {if (in != null) {try {in.close();} catch (IOException e) {log.error("close file error:", e);}}}if (ruleConfig == null) {throw new RuntimeException("can not load dark rule.");}// 更新规则并非直接在this.rule上进行// 而是通过创建一个新的 DarkRule,然后赋值给this.rule// 来避免更新规则和规则查询的并发冲突问题DarkRule darkRule = new DarkRule(ruleConfig);this.rule = darkRule;}public DarkFeature getDarkFeature(String featureKey) {return this.rule.getDarkFeature(featureKey);}
}

**再来看下 DarkRuleConfig 类。**这个类功能非常简单,只是用来将灰度规则映射到内存中。

public class DarkRuleConfig {private List<DarkFeatureConfig> features;public List<DarkFeatureConfig> getFeatures() {return features;}public void setFeatures(List<DarkFeatureConfig> features) {this.features = features;}public static class DarkFeatureConfig {private String key;private boolean enable;private String rule;public String getKey() {return key;}public void setKey(String key) {this.key = key;}public boolean isEnable() {return enable;}public void setEnable(boolean enable) {this.enable = enable;}public String getRule() {return rule;}public void setRule(String rule) {this.rule = rule;}}
}

从代码中,我们可以看出来,DarkRuleConfig 类嵌套了一个内部类 DarkFeatureConfig。这两个类跟配置文件中的两层嵌套结构完全对应 。

# 对应DarkRuleConfig
features:
- key: call_newapi_getUserById   # 对应DarkFeatureConfigenabled: truerule: {893,342,1020-1120,%30}
- key: call_newapi_registerUser  # 对应DarkFeatureConfigenabled: truerule: {1391198723, %10}
- key: newlog_loan               # 对应DarkFeatureConfigenabled: truerule: {0-1000}

再来看下 DarkRuleDarkRule 包含所有要灰度的业务功能的灰度规则。它用来支持根据业务功能标识(feature key),快速查询灰度规则(DarkFeture)。

public class DarkRule {private Map<String, DarkFeature> darkFeatures = new HashMap<>();public DarkRule(DarkRuleConfig darkRuleConfig) {List<DarkRuleConfig.DarkFeatureConfig> darkRuleConfigFeatures = darkRuleConfig.getFeatures();for (int i = 0; i < darkRuleConfigFeatures.size(); i++) {DarkRuleConfig.DarkFeatureConfig darkFeatureConfig = darkRuleConfigFeatures.get(i);darkFeatures.put(darkFeatureConfig.getKey(), new DarkFeature(darkFeatureConfig));}}public DarkFeature getDarkFeature(String featureKey) {return this.darkFeatures.get(featureKey);}
}

最后,我们来看下 DarkFeature 类。 DarkFeature 类标识每个要灰度的业务功能的灰度规则。DarkFeature 将配置文件中的灰度规则,解析成一定的结构(比如 RangeSet),方便快速判定某个灰度对象是否落在灰度规则范围内。

public class DarkFeature {private String key;private boolean enabled;private int percentage;private RangeSet<Long> rangeSet = TreeRangeSet.create();public DarkFeature(DarkRuleConfig.DarkFeatureConfig darkFeatureConfig) {this.key = darkFeatureConfig.getKey();this.enabled = darkFeatureConfig.isEnable();String darkRule = darkFeatureConfig.getRule().trim();parseDarkRule(darkRule);}@VisibleForTestingprotected void parseDarkRule(String darkRule) {if (!darkRule.startsWith("{") && !darkRule.endsWith("}")) {throw new RuntimeException("failed to parse dark rule: " + darkRule);}String[] rules = darkRule.substring(1, darkRule.length() - 1).split(",");this.rangeSet.clear();this.percentage = 0;for (String rule : rules) {rule = rule.trim();if (StringUtils.isEmpty(rule)) {continue;}if (rule.startsWith("%")) {this.percentage = Integer.parseInt(rule.substring(1));} else if (rule.contains("-")) {String[] parts = rule.split("-");if (parts.length != 2) {throw new RuntimeException("failed to parse dark rule: " + darkRule);}long start = Long.parseLong(parts[0]);long end = Long.parseLong(parts[1]);if (start > end) {throw new RuntimeException("failed to parse dark rule: " + darkRule);}this.rangeSet.add(Range.closed(start, end));} else {long val = Long.parseLong(rule);this.rangeSet.add(Range.closed(val, val));}}}public boolean isEnabled() {return enabled;}public boolean dark(long darkTarget) {boolean selected = this.rangeSet.contains(darkTarget);if (selected) {return true;}long reminder = darkTarget % 100;if (reminder > 0 && reminder < this.percentage) {return true;}return false;}public boolean dark(String darkTarget) {long target = Long.parseLong(darkTarget);return dark(target);}
}

添加、优化灰度组件

在第一步中,我们完成了灰度组件的基本功能。在第二步中,我们再实现基于编程的灰度规则配置方式,用来支持更复杂、更加灵活的灰度规则。

我们需要对第一步实现的代码,进行一些改造。改造之后的目录结构如下所示。其中,DarkFeatureDarkRuleConfig 的代码基本不变, 新增了 IDarkFeature 接口,DarkLaunchDarkRule 的代码有所改动,用来支持编程实现灰度规则。

// 第一步的代码目录结构
com.example.darklaunch--DarkLaunch (框架的最顶层入口类)--DarkFeature (每个feature的灰度规则)--DarkRule (灰度规则)--DarkRuleConfig (用来映射配置到内存中)// 第二步的代码目录结构
com.example.darklaunch--DarkLaunch (框架的最顶层入口类,代码有所改动)--IDarkFeature (抽象接口)--DarkFeature (实现IDarkFeature接口,基于配置文件的灰度规则,代码不变)--DarkRule (灰度规则,代码有改动)--DarkRuleConfig (用来映射配置到内存中,代码不变)

我们先来看下 IDarkFeature 接口,它用来抽象从配置文件中得到的灰度规则,以及编程实现的灰度规则。具体代码如下所示:

public interface IDarkFeature {boolean isEnabled();boolean dark(long darkTarget);boolean dark(String darkTarget);
}

基于这个抽象接口,业务系统可以自己编程实现复杂的灰度规则,然后添加到 DarkRule 中。为了避免配置文件中的灰度规则热更新时,覆盖编程实现的灰度规则,在 DarkRule 中,我们对从配置文件中加载的灰度规则和编程实现的灰度规则分开存储。按照这个设计思路,我们对 DarkRule 类进行重构。重构之后的代码如下所示:

public class DarkRule {// 从配置文件中加载的灰度规则private Map<String, IDarkFeature> darkFeatures = new HashMap<>();// 编程实现的灰度规则private Map<String, IDarkFeature> programmedDarkFeatures = new ConcurrentHashMap<>();public void addProgrammingDarkFeature(String featureKey, IDarkFeature darkFeature) {programmedDarkFeatures.put(featureKey, darkFeature);}public void setDarkRuleFeatures(Map<String, IDarkFeature> newDarkFeatures) {this.darkFeatures = newDarkFeatures;}public IDarkFeature getDarkFeature(String featureKey) {IDarkFeature darkFeature = programmedDarkFeatures.get(featureKey);if (darkFeature != null) {return darkFeature;}return this.darkFeatures.get(featureKey);}
}

因为 DarkRule 代码有所修改,对应地, DarkLaunch 的代码也需要做少许改动,主要有一处修改和一处新增代码,具体如下所示。

public class DarkLaunch {private static final Logger log = LoggerFactory.getLogger(DarkLaunch.class);private static final int DEFAULT_RULE_UPDATE_TIME_INTERVAL = 60; // in secondsprivate DarkRule rule;private ScheduledExecutorService executor;public DarkLaunch(int ruleUpdateTimeInterval) {loadRule();this.executor = Executors.newSingleThreadScheduledExecutor();this.executor.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {loadRule();}}, ruleUpdateTimeInterval, ruleUpdateTimeInterval, TimeUnit.SECONDS);}public DarkLaunch() {this(DEFAULT_RULE_UPDATE_TIME_INTERVAL);}private void loadRule() {// 将灰度规则配置文件dark-rule.yaml中的内容读取到DarkRuleConfig中InputStream in = null;DarkRuleConfig ruleConfig = null;try {in = this.getClass().getResourceAsStream("dark-rule.yaml");if (in != null) {Yaml yaml = new Yaml();ruleConfig = yaml.loadAs(in, DarkRuleConfig.class);}} finally {if (in != null) {try {in.close();} catch (IOException e) {log.error("close file error:", e);}}}if (ruleConfig == null) {throw new RuntimeException("can not load dark rule.");}// 修改:单独更新从配置文件中得到的灰度规则Map<String, IDarkFeature> darkFeatures = new HashMap<>();List<DarkRuleConfig.DarkFeatureConfig> darkFeatureConfigs = ruleConfig.getFeatures();for (DarkRuleConfig.DarkFeatureConfig darkFeatureConfig : darkFeatureConfigs) {darkFeatures.put(darkFeatureConfig.getKey(), new DarkFeature(darkFeatureConfig));}this.rule.setDarkRuleFeatures(darkFeatures);}// 新增,添加编程实现的灰度规则的接口public void addProgrammingDarkFeature(String featureKey, IDarkFeature darkFeature) {this.rule.addProgrammingDarkFeature(featureKey, darkFeature);}public IDarkFeature getDarkFeature(String featureKey) {return this.rule.getDarkFeature(featureKey);}
}

灰度组件的代码实现完了。我们在通过一个 Demo 看下,目前实现的灰度组件该如何使用。结合着 Demo,再去理解上面的代码,会更容易些。

// 灰度规则配置(dark-rule.yaml), 放到classpath路径下
features:
- key: call_newapi_getUserByIdenabled: truerule: {893,342,1020-1120,%30}
- key: call_newapi_registerUserenabled: truerule: {1391198723, %10}
- key: newlog_loanenabled: truerule: {0-1000}// 编程实现的灰度规则
public class UserPromotionDarkRule implements IDarkFeature {@Overridepublic boolean isEnabled() {return true;}@Overridepublic boolean dark(long darkTarget) {// 灰度规则自己想怎么写就怎么写return false;}@Overridepublic boolean dark(String darkTarget) {// 灰度规则自己想怎么写就怎么写return false;}
}// demo
public class Demo {public static void main(String[] args) {DarkLaunch darkLaunch = new DarkLaunch(); // 默认加载classpath下的dark-rule.yaml文件中的灰度规则darkLaunch.addProgrammingDarkFeature("user_promotion", new UserPromotionDarkRule());IDarkFeature darkFeature = darkLaunch.getDarkFeature("user_promotion");System.out.println(darkFeature.isEnabled());System.out.println(darkFeature.dark(833));}
}

总结

到本章为止,项目实战环节就彻底结束了。在这一部分中,我们通过限流、幂等、灰度这三个实战项目,带你从需求分析、系统设计、代码实现三个环节,学习了如何进行功能性、非功能性需求分析,如何通过合理的设计,完成功能性需求,满足非功能性需求,以及如何编写高质量的代码实现。

实际上,项目本身的分析、设计、实现并不重要,不必对细节过于纠结。希望通过这三个例子,分享思考思路、开发套路,让你借鉴并举一反三地应用到你的项目开发中。这才是最有价值的,才是你学习的重点。

相关文章:

设计模式学习笔记 - 项目实战三:设计实现一个支持自定义规则的灰度发布组件(实现)

概述 上两篇文章&#xff0c;我们讲解了灰度组件的需求和设计的思路。不管之前讲的限流、幂等框架&#xff0c;还是现在讲的灰度组件&#xff0c;功能性需求都不复杂&#xff0c;相反&#xff0c;非功能性需求是开发的重点。 本章&#xff0c;按照上篇文章的灰度组件的设计思…...

BJFUOJ-C++程序设计-实验2-类与对象

A 评分程序 答案&#xff1a; #include<iostream> #include<cstring>using namespace std;class Score{ private:string name;//记录学生姓名double s[4];//存储4次成绩&#xff0c;s[0]和s[1]存储2次随堂考试&#xff0c;s[2]存储期中考试&#xff0c;s[3]存储期…...

数据库语法复习

总结&#xff1a; DDL&#xff08;数据定义语言&#xff09; CREATE DATABASE&#xff1a;创建一个新的数据库。DROP DATABASE&#xff1a;删除一个数据库。CREATE TABLE&#xff1a;创建一个新的表。DROP TABLE&#xff1a;删除一个表。ALTER TABLE&#xff1a;修改表的结构&a…...

Tomcat、MySQL、Redis最大支持说明

文章目录 一、Tomcat二、MySQL三、Redis1、最大连接数2、TPS、QPS3、key和value最大支持 一、Tomcat 查看SpringBoot内置Tomcat的源码&#xff0c;如下&#xff1a; 主要就是看抽象类AbstractEndpoint&#xff0c;可以看到默认的核心线程数10&#xff0c;最大线程数200 通过…...

MATLAB数值计算工具箱介绍

MATLAB是一个强大的数学计算平台&#xff0c;它提供了广泛的数值计算工具箱&#xff0c;这些工具箱覆盖了从基础的线性代数到复杂的数值分析和优化问题。以下是MATLAB中一些关键工具箱的详细介绍&#xff1a; 1. 线性代数工具箱&#xff08;Linear Algebra Toolbox&#xff09…...

2023 广东省大学生程序设计竞赛(部分题解)

目录 A - Programming Contest B - Base Station Construction C - Trading D - New Houses E - New but Nostalgic Problem I - Path Planning K - Peg Solitaire A - Programming Contest 签到题&#xff1a;直接模拟 直接按照题目意思模拟即可&#xff0c;为了好去…...

ROS2学习——Docker环境下安装于使用(1)

目录 一、简要 二、ROS2和ROS1区别 三、环境搭建与安装 &#xff08;2&#xff09;拉取ubuntu22.04镜像 &#xff08;2&#xff09;安装ROS2 1. 基本设置 2.设置源 3.安装ROS2功能包 4.测试 四、相关指令学习 1.小海龟测试 2.ros2 node等指令 3.rqt 一、简要 随着R…...

数据仓库之Hologres

官方文档 简介 Hologres是阿里云推出的一种云原生的实时分析型数据仓库。它是基于开源项目Apache Hudi&#xff08;Hadoop Upserts Deletes and Incrementals&#xff09;进行扩展和优化的。Hologres提供了高性Hologres是阿里云推出的一种云原生的实时分析型数据仓库。它是基…...

MacOS搭建docker本地私有镜像库

相关环境 macOS: bigsur 11.7.8 docker desktop: 4.22.0 docker engine: 24.0.5 准备工作 本机已经安装好docker desktop&#xff0c;未安装的自行参考其他教程。如果不能翻墙&#xff0c;可以修改本地的镜像地址&#xff0c;可在docker desktop 设置中的docker engine中修…...

Unity Material(材质)、Texture(纹理)、Shader(着色器)简介

文章目录 一、概念二、Rendering Mode三、Main Maps三、参考文章 一、概念 Material(材质)&#xff1a;物体的“色彩”、“纹理”、“光滑度”、“透明度”、“反射率”、“折射率”、“发光度”等&#xff0c;材质的本质是shader的实例(载体)Texture(贴图)&#xff1a;附件到…...

《视觉十四讲》例程运行记录(1)—— 课本源码下载和3rdparty文件夹是空的解决办法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、第二版十四讲课本源码下载1. 安装git工具 二、Pangolin下载和安装1. 源码下载2. Pangolin的安装(1) 安装依赖项(2) 源码编译安装(2) 测试是否安装成功 二、…...

VLM与基础分割模型的联合使用

最近做的项目里有涉及大模型&#xff0c;里面有一部分的功能是&#xff1a; 将图片输入VLM(视觉语言模型&#xff0c;我使用的是llava)&#xff0c;询问图中最显著的物体&#xff0c;将其给出的答案作为基础分割模型&#xff08;我使用的是Grounded-SAM&#xff09;的text prom…...

JS数组去重的方法

目录 1、includes 2、indexOf 3、Set结合Array.from 4、filter 5、reduce 6、使用双重for循环 介绍一下数组常用的去重复方法 以以下数组为例子来介绍&#xff0c;一维的数字类型数组&#xff1a; const arr [1, 2, 2, 2, 3, 1, 6, 4, 4, 6, 5, 7] 1、includes funct…...

Go实战训练之Web Server 与路由树

Server & 路由树 Server Web 核心 对于一个 Web 框架&#xff0c;至少要提供三个抽象&#xff1a; Server&#xff1a;代表服务器的抽象Context&#xff1a;表示上下文的抽象路由树 Server 从特性上来说&#xff0c;至少要提供三部分功能&#xff1a; 生命周期控制&…...

C#中接口设计相关原则

在C#中&#xff0c;接口&#xff08;Interface&#xff09;是一种引用类型&#xff0c;它定义了一个契约&#xff0c;指定了一个类必须实现的成员&#xff08;属性、方法、事件、索引器&#xff09;。接口不提供这些成员的实现&#xff0c;只指定成员必须按照特定的方式被实现。…...

Pytorch学习笔记——卷积操作

一、认识卷积操作 卷积操作是一种数学运算&#xff0c;它涉及两个函数&#xff1a;输入函数&#xff08;通常是图像&#xff09;和卷积核&#xff08;也称为滤波器或特征检测器&#xff09;。卷积核在输入函数上滑动&#xff0c;将核中的每个元素与其覆盖的输入函数区域中的对应…...

探索鸿蒙开发:鸿蒙系统如何引领嵌入式技术革新

嵌入式技术已经成为现代社会不可或缺的一部分。而在这个领域&#xff0c;华为凭借其自主研发的鸿蒙操作系统&#xff0c;正悄然引领着一场技术革新的浪潮。本文将探讨鸿蒙开发的特点、优势以及其对嵌入式技术发展的深远影响。 鸿蒙操作系统的特点 鸿蒙&#xff0c;作为华为推…...

chrome extension插件替换网络请求中的useragent

感觉Chrome商店中的插件不能很好的实现自己想要的效果,那么就来自己动手吧。 本文以百度为例: 一般来说网页请求如下: 当前使用的useragent是User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safar…...

PHP基础【介绍,注释,更改编码,赋值,数据类型】

源码 <?php //单行注释 /* 多行注释 *///通过header()函数发送http头的请求信息用来指定页面的字符集编码 header("Content-type:text/html;Charsetutf-8"); //告诉浏览器&#xff0c;当前页面的内容类型是HTML&#xff0c;并且页面内容使用的是UTF-8编码。//ph…...

ASP.NET小型证券术语解释及翻译系统的设计与开发

摘 要 在系统设计上&#xff0c;综合各种翻译类型网站优缺点&#xff0c;设计出具有任何使用者都可添加术语信息的且只有管理员能够实现术语修改及删除等独特方式的术语查看管理系统。此方式能够使术语量快速增大&#xff0c;并且便于使用者及管理员操作&#xff0c;满足相互…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...