bootstrap商城模板/杭州seo的优化
某个项目里有一段老代码写的不是很好,想着能否通过自己掌握的知识,将其改善一下。感兴趣的小伙伴可以通过了解背景和需求,自己试想下该如何实现,如果有更好的方案也欢迎留言讨论。
1. 背景及需求
(1) 背景
假设我们的下游提供了一个定时任务接口CronJob(cron string, fun func())
,它的入参有两个,分别是定时任务执行的频率,以及具体执行哪个函数。我们要借助该定时任务接口实现一个功能:对数据库中同一张表的所有数据的两个不同的字段完成赋值。为了给每个字段赋值,会分别设置两个定时任务,一个是正常的任务处理,5分钟执行一次,负责捞取最近30分钟的数据并完成赋值。另一个是补偿的任务处理,1小时执行一次,负责捞取最近24小时的数据并完成赋值。
(2) 需求
代码的实现要满足以下要求:
- 因为都是捞取同一张表的数据并完成赋值,所以该部分代码应该复用同一份代码,防止出错;
- 后续可能有新增字段需要类似的赋值逻辑,所以代码应该有良好的可扩展性;
- 由于只有字段赋值逻辑不同,所以每次新增字段赋值需求时,代码的改动应该尽可能小。
2. 需求分析及实现
(1) 定时任务代码
由于我们依赖下游的定时任务接口,所以首先给出模拟的定时任务接口。
// CronJob 模拟定时任务,参数分别为调度时间和调度内容
func CronJob(cron string, fun func()) {fmt.Println("调度时间: ", cron)fmt.Println("定时任务执行开始。。。")fun()fmt.Println("定时任务执行结束。。。\n\n")
}
(2) 定义接口
我们需要实现的是对字段的赋值方法,由于同一字段的赋值,分为了正常的任务处理和补偿的任务处理两个,所以我们可以定义两个接口方法Common
和Fix
。
// ProcessJob 处理任务接口,定义了两个方法
type ProcessJob interface {Common(name string) func() // 正常的任务处理Fix(name string) func() // 补偿的任务处理
}
(3) 接口的实现类
定义了接口后,接口的实现类应该分别实现上述两个方法,完成两个字段的赋值逻辑。而从数据库捞取数据的部分显然是通用的,该部分可以独立成为一个函数,该函数可以捞取数据,并将数据的主键id传参给实现类的两个方法,完成该条数据的赋值。
1) 通用部分
正常和补偿任务处理中通用的部分:
// Common 正常的任务处理中通用的部分
func Common(name string, fun func(params string)) func() {id := "$模拟id$"return func() {fmt.Println("任务名称为:", name)fmt.Println("正常任务处理的前置操作。。。")fun(id)fmt.Println("正常任务处理的后置操作。。。")}
}// Fix 补偿的任务处理中通用的部分
func Fix(name string, fun func(params string)) func() {id := "$模拟id$"return func() {fmt.Println("任务名称为:", name)fmt.Println("补偿任务处理的前置操作。。。")fun(id)fmt.Println("补偿任务处理的后置操作。。。")}
}
注意下通用方法的入参,这里分别用来接收实现类方法传入的参数,以及字段赋值逻辑的函数。
2) 第一个接口实现类
第一个处理任务,为第一个字段赋值:
// ProcessJob1 第一个处理任务,为第一个字段赋值
type ProcessJob1 struct{}// Common 第一个处理任务的正常任务处理
func (pj ProcessJob1) Common(name string) func() {return Common(name, func(id string) {fmt.Printf("常规任务处理中,为id为 %v 的第一个字段进行赋值", id)})
}// Fix 第一个处理任务的补偿任务处理
func (pj ProcessJob1) Fix(name string) func() {return Fix(name, func(id string) {fmt.Printf("补偿任务处理中,为id为 %v 的第一个字段进行赋值", id)})
}
这里需要注意下,由于定时任务接口只接受类型为func()
的函数,所以接口实现类的Common
和Fix
方法的返回值都是func()
类型。而字段赋值逻辑函数的入参为从通用函数那传入的参数,即数据的主键id。
3) 第二个接口实现类
第二个处理任务,为第二个字段赋值:
// ProcessJob2 第二个处理任务,为第二个字段赋值
type ProcessJob2 struct{}// Common 第二个处理任务的正常任务处理
func (pj ProcessJob2) Common(name string) func() {return Common(name, func(id string) {fmt.Printf("常规任务处理中,为id为 %v 的第二个字段进行赋值", id)})
}// Fix 第二个处理任务的补偿任务处理
func (pj ProcessJob2) Fix(name string) func() {return Fix(name, func(id string) {fmt.Printf("补偿任务处理中,为id为 %v 的第二个字段进行赋值", id)})
}
(4) 实现类再封装
由于ProcessJob1和ProcessJob2都可以看做是ProcessJob类型,所以可以为实现类再封装一层,以便统一进行处理。通过分析需求可以知道,实现类的属性可以有任务名称、正常任务处理的调度时间、补偿任务处理的调度时间等组成,所以可以定义以下类型:
// JobConf 定时任务配置
type JobConf struct {Name string // 定时任务的名称CommonCron string // 正常任务处理的调度时间FixCron string // 补偿任务处理的调度时间ProcessJob ProcessJob // 处理任务对象
}
(5) 添加/获取任务配置
定义了统一的类型之后,就可以创建一个该类型的列表,如果有新增的字段赋值需求,那么就可以很方便的进行扩展了,只需要在列表中新增一个任务配置即可。
// GetJobConfMap 获取所有的任务配置信息
func GetJobConfMap() map[string]JobConf {// 定义一个任务配置的列表,如有新增的任务,直接append一个新任务即可jobConfList := make([]JobConf, 0)jobConfList = append(jobConfList, JobConf{Name: "job1",CommonCron: "1 * * * * *",FixCron: "11 * * * * *",ProcessJob: ProcessJob1{},})jobConfList = append(jobConfList, JobConf{Name: "job2",CommonCron: "2 * * * * *",FixCron: "22 * * * * *",ProcessJob: ProcessJob2{},})// 获取任务名到任务配置的mapjobConfMap := make(map[string]JobConf)for _, jobConf := range jobConfList {jobConfMap[jobConf.Name] = jobConf}return jobConfMap
}
(6) 主函数
最后就是根据每个任务的配置,启动对应的定时任务了。
func main() {// 获取所有的任务配置信息jobConfMap := GetJobConfMap()// 为每个任务独立设置调度时间,以及处理内容for jobName, jobConf := range jobConfMap {processJob := jobConf.ProcessJobCronJob(jobConf.CommonCron, processJob.Common(jobName))CronJob(jobConf.FixCron, processJob.Fix(jobName))}
}
3. 完整代码
package mainimport ("fmt"
)// CronJob 模拟定时任务,参数分别为调度时间和调度内容
func CronJob(cron string, fun func()) {fmt.Println("调度时间: ", cron)fmt.Println("定时任务执行开始。。。")fun()fmt.Println("定时任务执行结束。。。\n\n")
}// ProcessJob 处理任务接口,定义了两个方法
type ProcessJob interface {Common(name string) func() // 正常的任务处理Fix(name string) func() // 补偿的任务处理
}// Common 正常的任务处理中通用的部分
func Common(name string, fun func(params string)) func() {id := "$模拟id$"return func() {fmt.Println("任务名称为:", name)fmt.Println("正常任务处理的前置操作。。。")fun(id)fmt.Println("正常任务处理的后置操作。。。")}
}// Fix 补偿的任务处理中通用的部分
func Fix(name string, fun func(params string)) func() {id := "$模拟id$"return func() {fmt.Println("任务名称为:", name)fmt.Println("补偿任务处理的前置操作。。。")fun(id)fmt.Println("补偿任务处理的后置操作。。。")}
}// JobConf 定时任务配置
type JobConf struct {Name string // 定时任务的名称CommonCron string // 正常任务处理的调度时间FixCron string // 补偿任务处理的调度时间ProcessJob ProcessJob // 处理任务对象
}// ProcessJob1 第一个处理任务,为第一个字段赋值
type ProcessJob1 struct{}// Common 第一个处理任务的正常任务处理
func (pj ProcessJob1) Common(name string) func() {return Common(name, func(id string) {fmt.Printf("常规任务处理中,为id为 %v 的第一个字段进行赋值", id)})
}// Fix 第一个处理任务的补偿任务处理
func (pj ProcessJob1) Fix(name string) func() {return Fix(name, func(id string) {fmt.Printf("补偿任务处理中,为id为 %v 的第一个字段进行赋值", id)})
}// ProcessJob2 第二个处理任务,为第二个字段赋值
type ProcessJob2 struct{}// Common 第二个处理任务的正常任务处理
func (pj ProcessJob2) Common(name string) func() {return Common(name, func(id string) {fmt.Printf("常规任务处理中,为id为 %v 的第二个字段进行赋值", id)})
}// Fix 第二个处理任务的补偿任务处理
func (pj ProcessJob2) Fix(name string) func() {return Fix(name, func(id string) {fmt.Printf("补偿任务处理中,为id为 %v 的第二个字段进行赋值", id)})
}// GetJobConfMap 获取所有的任务配置信息
func GetJobConfMap() map[string]JobConf {// 定义一个任务配置的列表,如有新增的任务,直接append一个新任务即可jobConfList := make([]JobConf, 0)jobConfList = append(jobConfList, JobConf{Name: "job1",CommonCron: "1 * * * * *",FixCron: "11 * * * * *",ProcessJob: ProcessJob1{},})jobConfList = append(jobConfList, JobConf{Name: "job2",CommonCron: "2 * * * * *",FixCron: "22 * * * * *",ProcessJob: ProcessJob2{},})// 获取任务名到任务配置的mapjobConfMap := make(map[string]JobConf)for _, jobConf := range jobConfList {jobConfMap[jobConf.Name] = jobConf}return jobConfMap
}func main() {// 获取所有的任务配置信息jobConfMap := GetJobConfMap()// 为每个任务独立设置调度时间,以及处理内容for jobName, jobConf := range jobConfMap {processJob := jobConf.ProcessJobCronJob(jobConf.CommonCron, processJob.Common(jobName))CronJob(jobConf.FixCron, processJob.Fix(jobName))}
}
相关文章:

【golang/go语言】Go语言代码实践——高复用、易扩展性代码训练
某个项目里有一段老代码写的不是很好,想着能否通过自己掌握的知识,将其改善一下。感兴趣的小伙伴可以通过了解背景和需求,自己试想下该如何实现,如果有更好的方案也欢迎留言讨论。 1. 背景及需求 (1) 背景 假设我们的下游提供了…...

[数据结构与算法(严蔚敏 C语言第二版)]第1章 绪论(学习复习笔记)
1.1 数据结构的研究内容 计算机解决问题的步骤 从具体问题抽象出数学模型设计一个解此数学模型的算法编写程序,进行测试、调试,直到解决问题 计算机解决问题的过程中寻求数学模型的实质是 分析问题,从中提取操作的对象,并找出这些…...

05_Pulsar的主要组件介绍与命令使用、名称空间、Pulsar的topic相关操作、Pulsar Topic(主题)相关操作_高级操作、
1.5.Apache Pulsar的主要组件介绍与命令使用 1.5.1.多租户模式 1.5.1.1. 什么是多租户 1.5.1.2.Pulsar多租户的相关特征_安全性(认证和授权) 1.5.1.3.Pulsar多租户的相关特性_隔离性 1.5.1.4.Pulsar多租户的相关操作 1-获取租户列表 2-创建租户 3-获取配…...

我的终端怎么莫名卡死了?shell下ctrl+s的含义
在终端下面一不小心按下了ctrl s,整个终端就锁住了,不知道原油的同学可能会以为终端卡死了,找不到原因只好关闭终端重新打开,然后下意识还不忘吐槽一句,垃圾ubuntu,动不动卡死。 事实上ctrl s在终端下是…...

【Vue】Vue的简单介绍与基本使用
一、什么是VueVue是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面,Vue 都可以胜任。1.构建用户界面传统方…...

网络知识篇
网络知识篇 局域网 当多台计算机或设备通过同一物理或逻辑连接(例如以太网或Wi-Fi网络)连接在一起,并且它们可以相互通信时,就构成了一个局域网(Local Area Network,LAN)。 子网划分 为了更…...

python 连接数据库
文章目录同步操作同步连Mysql同步连redis同步连mongodb异步操作异步连mysql异步连redis异步连mongodb同步操作 同步连Mysql python 连接mysql可以使用pymysql、mysqlclient等。 安装: # win pip install pymysql 连接mysql: # __author__ "laufing"…...

一文讲明白一致性hash算法
一致性Hash算法常用来解决数据分片时的数据扩容/缩容的性能问题。 一、业内数据分片用的Hash算法,将节点的hash值对节点数取余。 存取通过key / value的方式对节点取余。 二、数据分片使用hash算法的优缺点: 优点:简单,方便。 缺…...

Java分布式解决方案(一)
随着互联网的不断发展,互联网企业的业务在飞速变化,推动着系统架构也在不断地发生变化。 如今微服务技术越来越成熟,很多企业都采用微服务架构来支撑内部及对外的业务,尤其是在高 并发大流量的电商业务场景下,微服务…...

设备树系统学习(二)设备树的节点和属性
一、节点 1.节点命名格式 格式:<name>[@<unit-address>] name:是一个简单的 ASCII 字符串,长度最多为 31 个字符,节节点是根据它所代表的设备类型来命名的,比如 “gpu” 就表示这个节点是 gpu外设。 unit-address:一般表示设备的地址或寄存器首地址,可以为…...

【数据结构】二叉树的基本操作中的一些易错点
文章目录前言一、求二叉树节点个数二、求树的叶子结点个数三、求树的高度四、二叉树查找值为x的结点总结前言 笔者整理出了一些关于萌新在入门二叉树时容易犯的一些错误,你也来试试自己会不会掉到这些坑里把~ 一、求二叉树节点个数 错误示例: int Tre…...

在线图书借阅网站( Python +Vue 实现)
功能介绍 平台采用B/S结构,后端采用主流的Python语言进行开发,前端采用主流的Vue.js进行开发。 整个平台包括前台和后台两个部分。 前台功能包括:首页、图书详情页、用户中心模块。后台功能包括:总览、借阅管理、图书管理、分类…...

不平衡数据集的建模的技巧和策略
不平衡数据集是指一个类中的示例数量与另一类中的示例数量显著不同的情况。 例如在一个二元分类问题中,一个类只占总样本的一小部分,这被称为不平衡数据集。类不平衡会在构建机器学习模型时导致很多问题。不平衡数据集的主要问题之一是模型可能会偏向多数…...

3. 算法效率
同一个问题的不同算法在性能上的比较,现在的方法主要是算法时间复杂度。算法效率是算法操作(operate)或处理(treat)数据的重复次数最小。 例题选自《编程珠玑》第8章,算法设计技术。 这个问题是一维模式识别(人工智能)中的一个问题。 输入有n个元素的向量,输出连续子向…...

仪表放大器放大倍数分析-运算放大器
仪表放大器是一种非常特殊的精密差分电压放大器,它的主要特点是采用差分输入、具有很高的输入阻抗和共模抑制比,能够有效放大在共模电压干扰下的信号。本文简单分析一下三运放仪表放大器的放大倍数。 一、放大倍数理论分析 三运放仪表放大器的电路结构…...

laravel8多模块、多应用和多应用路由
1、安装多应用模块 composer require nwidart/laravel-modules2、执行命令,config文件夹下生成一个modules.php配置文件 php artisan vendor:publish --provider"Nwidart\Modules\LaravelModulesServiceProvider"3、修改config文件夹下的modules.php&am…...

【Java学习笔记】6.Java 变量类型
Java 变量类型 在Java语言中,所有的变量在使用前必须声明。声明变量的基本格式如下: type identifier [ value][, identifier [ value] ...] ;格式说明:type为Java数据类型。identifier是变量名。可以使用逗号隔开来声明多个同类型变量。 …...

Promise对象状态属性 工作流程 Promise对象的几个属性
Promise 对象状态属性介绍 实例对象中的一个属性 PromiseState pending 1、pending 变为 resolved / fullfilled 成功 2、pending 变为 rejected 失败 说明:只有这2种,且一个promise对象只能改变一次 无论变为成功还是失败,都会有一个结果…...

webgpu思考obj携带属性
今天在搞dbbh.js的时候,想到一个问题,啥问题呢,先看看情况 画2个材质不相同的box的时候 首先开始createCommandEncoder,然后beginRenderPass,分歧就在这里了 第一个box,他有自己的pipeline,第二个也有,那么…...

设计模式(只谈理解,没有代码)
1.什么是设计模式设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。2.为什么要学习设计模式看懂源代码:如果你不懂设计模式去看Jd…...

06、Eclipse 中使用 SVN
Eclipse 中使用 SVN1 在 Eclipse 中安装 SVN 客户端插件1.1 在线安装1.2 离线安装2 SVN 在 Eclipse 分享3 检出提交更新3.1 检出3.2 提交3.3 更新4 Eclipse 中 SVN 图标及其含义4.1 ?图标4.2 图标4.3 金色圆柱图标4.4 * 图标5 恢复历史版本5.1 恢复步骤5.2 权限控制…...

Zookeeper3.5.7版本——客户端命令行操作(命令行语法)
目录一、命令行语法二、help命令行语法示例一、命令行语法 命令行语法列表 命令基本语法功能描述help显示所有操作命令ls path使用 ls 命令来查看当前 znode 的子节点 [可监听]-w 监听子节点变化-s 附加次级信息create普通创建-s 含有序列-e 临时(重启或者超时消失…...

2023.03.05 学习周报
文章目录摘要文献阅读1.题目2.摘要3.介绍4.SAMPLING THE OUTPUT5.LOSS FUNCTION DESIGN5.1 ranking loss: Top1 & BPR5.2 VANISHING GRADIENTS5.3 ranking-max loss fuction5.4 BPR-max with score regularization6.实验7.结论深度学习1.相关性1.1 什么是相关性1.2 协方差1…...

java Spring JdbcTemplate配合mysql实现数据批量修改
其实这个操作和批量添加挺像的 调的同一个方法 首先 我们看数据库结构 这是我本地的 mysql 里面有一个test数据库 里面有一张user_list表 然后创建一个java项目 然后 引入对应的JAR包 在src下创建 dao 目录 在下面创建一个接口 叫 BookDao 参考代码如下 package dao;impo…...
《算法分析与设计》笔记总结
《算法分析与设计》笔记总结第一章 算法引论1.1 算法与程序1.2 表达算法的抽象机制1.3 描述算法1.4 算法复杂性分析第二章 递归与分治策略2.1 递归的概念2.2 分治法的基本思想2.3 二分搜索技术2.4 大整数乘法2.5 Strassen矩阵乘法2.7 合并排序2.8 快速排序2.9 线性时间选择2.10…...

序列化与反序列化概念
序列化是指将对象的状态信息转换为可以存储或传输的形式的过程。 在Java中创建的对象,只要没有被回收就可以被复用,但是,创建的这些对象都是存在于JVM的堆内存中,JVM处于运行状态时候,这些对象可以复用, 但…...

【Java并发编程】CountDownLatch
CountDownLatch是JUC提供的解决方案 CountDownLatch 可以保证一组子线程全部执行完牛后再进行主线程的执行操作。例如,主线程启动前,可能需要启动并执行若干子线程,这时就可以通过 CountDownLatch 来进行控制。 CountDownLatch是通过一个线程…...

【iOS】Blocks
BlockBlocks概要什么是Blocks?Block语法Block类型变量截获自动变量值__block说明符Blocks的实现Block的实质Blocks概要 什么是Blocks? Blocks可简单概括为: 带有自动变量(局部变量)的匿名函数 在使用Blocks时&#x…...

Java Volatile的三大特性
本文通过学习:周阳老师-尚硅谷Java大厂面试题第二季 总结的volatile相关的笔记volatile是Java虚拟机提供的轻量级的同步机制,三大特性为:保证可见性、不保证原子性、禁止指令重排一、保证可见性import java.util.concurrent.TimeUnit;class M…...

Android Compose——一个简单的Bilibili APP
Bilibili移动端APP简介依赖效果登录效果WebView自定义TobRow的Indicator大小首页推荐LazyGridView使用Paging3热门排行榜搜索模糊搜索富文本搜索结果视频详情合集信息Coroutines进行网络请求管理,避免回调地狱添加suspendwithContextGit项目链接末简介 此Demo采用A…...