如何使用高阶函数编程提升代码的简洁性

摘要

函数是 Go 言语的一等公民,本文选用一种高阶函数的办法,笼统了运用 gorm 查询 DB 的查询条件,将多个表的各种杂乱的组合查询笼统成了一个一致的办法和一个装备类,提升了代码的简练和优函数式编程雅,一起可以提升开发java是什么意思人员的效率。

背景

有一张 DB 表,事务上需求依照shell什么意思这个表里指针万用表读数图解的不同字段做挑选查询,这函数式编程是一个十分变量遍及的需求,我信任这种需求关于每个做业指针务开发的人都是绕不开的。比方咱们有一张存储用户信息的表,简化之后的表结构如下:

CREATETABLE`user_info`(
`id`bigintunsignedNOTNULLAUTO_INCREMENTCOMMENT'自增主键',
`user_id`bigintNOTNULLCOMMENT'用户id',
`user_name`varcharNOTNULLCOMMENT'用户姓名',
`role`intNOTNULLDEFAULT'0'COMMENT'人物',
`status`intNOTNULLDEFAULT'0'COMMENT'状况',
PRIMARYKEY(`id`),
)ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COMMENT='用户信息表';

这个表里有变量类型有哪些几个关键字段,user_id、user_name 、 role、status。假如咱们想依照 user_id 来做挑选,那咱们一指针数组般是在 dao 层Shell写一个shell编程这样的办法(为了shell编程示例代码的简练,这shell什么意思儿一切示例代码shell编程都省去了错变量是什么意思误处理部分):

funcGetUserInfoByUid(ctxcontext.Context,userIDint64)([]*resource.UserInfo){
db:=GetDB(ctx)
db=db.Table(resource.UserInfo{}.TableName())
varinfos[]*resource.UserInfo
db=db.Where("user_id=?",userID)
db.Find(&infos)
returninfos
}

假如事务上又需求依照 user_name 来查询,那咱们就需求再写一shell编程个类似的办法依照 user_name 来查询:

funcGetUserInfoByName(ctxcontext.Context,namestring)([]*resource.UserInfo){
db:=GetDB(ctx)
db=db.Table(resource.UserInfo{}.TableName())
varinfos[]*resource.UserInfo
db=db.Where("user_name=?",name)
db.Find(&infos)
returninfos
}

可以java环境变量装备看到,两个办法的代码极度相似,假如再需求按javjava语言a怎样读照 role 或许 status 查询,那不得不再来几个办法,导致相似的办法十分多。当然很简略想到,咱们可以用一个办法,多几个入参的办法来处理这个问题,所以,咱们把上面两个办法变量名兼并成下面这种办法,可以支撑依照多个字段挑选查询

funcGetUserInfo(ctxcontext.Context,userIDint64,namestring,roleint,statusint)([]*resource.UserInfo){
db:=GetDB(ctx)
db=db.Table(resource.UserInfo{}.TableName())
varinfos[]*resource.UserInfo
ifuserID>0{
db=db.Where("user_id=?",userID)
}
ifname!=""{
db=db.Where("user_name=?",name)
}
ifrole>0{
db=db.Where("role=?",role)
}
ifstatus>0{
db=db.Where("status=?",status)
}
db.Find(&infos)
returninfos
}

相应地,调用该办法的代码也需javaeejava培训要做出改变:

//只依据UserID查询
infos:=GetUserInfo(ctx,userID,"",0,0)
//只依据UserName查询
infos:=GetUserInfo(ctx,0,name,0,0)
//只依据Role查询
infos:=GetUserInfo(ctx,0,"",role,0)
//只依据Status查询
infos:=GetUserInfo(ctx,0,"",0,status)

这种java编译器代码无论是写代码的人还是读代码的人,指针万用表读数图java是什么意思都会感觉十分难受。咱们这儿只列举了四个参数,可以想想这个表里假如有十指针数组几个到二十个字段都需求做挑选查询,这种代shell怎样读码看上去是一种什么样的感觉。首先,GetUserInfoshell什么意思 办法自身入参十分多,里面充斥着各种 != 0 和 != “”的判别,而且需求留意的是,0 必定不能作为字段的有效值,不然 != 0 这种判别就会有问题。其次,作为调用方,明指针式万用表指针明仅仅依据一个字段挑选查询,却不java是什么意思得不为其他参数填充一个 0 或许””来占位,而且调用者要特别谨慎,因为一不小心,就可能会把 role 填到了 status 的位置上指针数组和数组指针的区别去,因为他们的类型javascript都相同,编译器不会检查出任何错变量名的命名规矩误,很简略搞出事务 bug。

处理方案

变量英语如说处理这种问题有段位,那么以上的写法只能算是青函数式编程铜,接下来咱们看看白银、黄金和王者。

白银

处理这种问题,一种比较常见的方案是,新建一个结构体,把各种查询的字段shellfish都放在这个结构体中,然后把这个结构体作为入参传入到 dao 层的查询办法中。而在调用 dao 办法的当地shell什么意思,依据各自的需求,构建包括不javascript同字段的结变量之间的联系构体。在这个比方中,咱们可以构建一个 UserInfo 的结构体如下:

typeUserInfostruct{
UserIDint64
Namestring
Roleint32
Statusint32
}

把 UserInfo 作为入参传给 GetUserInfshell什么意思o 办法shell什么意思,所以 GetUserInfo 办法变成了这样:

funcGetUserInfo(ctxcontext.Context,info*UserInfo)([]*resource.UserInfo){
db:=GetDB(ctx)
db=db.Table(resource.UserInfo{}.TableName())
varinfos[]*resource.UserInfo
ifinfo.UserID>0{
db=db.Where("user_id=?",info.UserID)
}
ifinfo.Name!=""{
db=db.Where("user_name=?",info.Name)
}
ifinfo.Role>0{
db=db.Where("role=?",info.Role)
}
ifinfo.Status>0{
db=db.Where("status=?",info.Status)
}
db.Find(&infos)
returninfos
}

相应地,调用该办法的代码也需求变化:

//只依据userD查询
info:=&UserInfo{
UserID:userID,
}
infos:=GetUserInfo(ctx,info)
//只依据name查询
info:=&UserInfo{
Name:name,
}
infos:=GetUserInfo(ctx,info)

这个代码写到这儿,比较最开端的办法其实已变量与函数经好了不少,至少 da指针数组和数组指针的区别o 层的办法从许多个入参变成了一变量,调用方的代码也shell怎样读可以依据自己的需求构建参数,不需求许shell脚本编程100例多空占位符。可是存在的问题也比较变量英语明显:依然有许多判空不说,还引进了一个剩余的结构体shell是什么意思中文假如咱们就到此结java语言束的话,多java言语少有点惋惜。

别的,假如咱们再扩展一下事务场景,咱们运用的不是等值查询,而是多值查询或许区间查询,比指针式万用表运用办法如查询 status in (a, b),那上面的代码又怎样扩指针万用表读数图解展呢?是不是又要引进一个办法,办法繁琐暂且不说,办法名叫啥都会让咱们java言语纠结很久;或许可以测验把每个参Shell数都从单值扩展成数组,然后赋值的当地从 = 改为 in()的办法,一切参数查询都运用 in 明显对功用不是那么友好。

黄金

接下来咱们看看变量名的命名规矩黄金的解法。在javaeejava怎么读面的办法中,咱们引Java进了一个剩余的结构体,而且无法防止在 dao 层的办法中指针做了许多判空java环境变量装备赋值。那么咱们能不能不引进 UserInfo 这个剩余的结构体,而且也防止这些丑陋的判空?答案是可以的,java面试题数式编程可以很好地解指针式万用表运用办法决这个问题,首先咱们需求界说一个函数类javascriptShell型:

typeOptionfunc(*gorm.DB)

界说 Option变量是什么意思 是一个函数,这个函数的Java入参类型是*gorm.DB,回来值为空。

然后针对 DB 表中每个需求挑选查询的字段界说一个函数,为这个字段赋值,像下面这样:

funcUserID(userIDint64)Option{
returnfunc(db*gorm.DB){
db.Where("`user_id`=?",userID)
}
}
funcUserName(namestring)Option{
returnfunc(db*gorm.DB){
db.Where("`user_name`=?",name)
}
}
funcRole(roleint32)Option{
returnfunc(db*gorm.DB){
db.Where("`role`=?",role)
}
}
funcStatus(statusint32)Option{
returnfunc(db*gorm.DB){
db.Where("`status`=?",status)
}
}

上面这组代码中java培训,入java培训参是一个字段的挑选值,回来的是一个 Option 函数,而这个函数的功用是把入参赋值给当前的【db *gorm.DB】目标。这也shell脚本便是咱们在文章一开端就说到的高阶函数,跟咱们一般的函数不太相同,一般的函数回来的是一个简略类型的值或许一个封javaee装类型的结构体,而这种高阶函数回来的是一个具备某种功用的函数。这儿多说一句,尽管 go 言语很好地支撑了函数式编程,可是由于其目前缺少对泛型的支shell脚本编程100例,导致高阶函数编程指针万用表读数图解的运用并没有给开发者shelly带来更多的便利,因而在平指针说漫时事务代java培训码中写高阶函数还java编译器是略为罕见。而了解 JAVA 的同学都知道,JAVA 中的 Ma变量的界说p、Reduce、Filter 等高java语言阶函数运用起来十分的舒服。

好,有了这一组函数之后,咱们来看看 dao 层的查变量之间的联系询办法怎样写:

funcGetUserInfo(ctxcontext.Context,options...func(option*gorm.DB))([]*resource.UserInfo){
db:=GetDB(ctx)
db=db.Table(resource.UserInfo{}.TableName())
for_,option:=rangeoptions{
option(db)
}
varinfos[]*resource.UserInfo
db.Find(&infos)
returninfos
}

js函数式编程有对比就没有伤害,经过和最开指针是什么始的办法比指针是什么较,可以看到办法的入参指针由多个不同类型的参数变成了一组相同类型的函数,因而在处理这函数式编程语言些参数的时分,也java面试题无需一个一个的判空,而是直接运用一个 for 循环指针数组和数组指针的差异就搞定,比较之前现已简练了许多。

那么调用该办法的代码怎样写呢,这儿直接给出来:

//只运用userID查询
infos:=GetUserInfo(ctx,UserID(userID))
//只运用userName查询
infos:=GetUserInfo(ctx,UserName(name))
//运用role和status一起查询
infos:=GetUserInfo(ctx,Role(role),Status(status))

无论是运用恣意的单个参数还是运用多个参数组合查询,咱们都随意写,不变量之间的关系必关注参数次序,简练又明晰,可读性也是十分好。

指针来考虑上面说到的扩展场景指针说漫,假如咱们需求多值查询,比方查询多shell翻译个 status,那shell脚本编程100例变量之间的关系么咱们只需求在 Opt变量名的命名规则ion 中添加一个小小的函数即可:

funcStatusIn(status[]int32)Option{
returnfunc(db*gorm.DB){
db.Where("`status`in?",status)
}
}

关于指针数学其他字段或许等值查询也是同理,代码的变量类型有哪些简练显而易见。

王者

能优化到上面黄金的阶段,其实现已很简练指针了,假如止步于此shellfish的话,也是完全可以的。可是假如还想进一步追求极致,那么请继续往下看!

在上面办法中,咱们经过高阶函数现已很好地处理了关于一张表中多字段组合查询的代码繁琐问题,可是关于不同的java面试题指针c言语查询,依然要针对每个表都写一个查询办法,那么shell指令有没有进java环境变量装备一步优化的空间呢?咱们shelly发现,在 Option 中界说的这一组高阶函数,压根与某张表没联系,他仅仅简略地给 gorm.DB 赋值。因而,如指针数学果咱们有多张表,每个表里都有 user_id、is_deleted、create_time、update_time 这些公共的字段,那shell什么意思么咱们完指针式万用表使用方法全不必再重复界说一次,只需求在 Option 中定shelly义一个就够了,每张表的查询都可以复用这些函数。进一步考虑,咱们发现,Option 中保护的指针万用表读数图解是一些傻瓜式的代码,底子不需求咱们每次手动去写,可以运用脚本生成,扫描一遍 DB 的表,为每个不重复的字段生成一个 Equal 办法指针式万用表、In 办法、Greater 办法、Less 办法,就可以处理一切表中依照不同字段做等值查询、多值查询、区间查询。

处理了 Option 的问题之后,关于每个表的各种组合查询,就只需求写一个很简略的 Get 办法了,为了方便指针万用表怎样读数看,咱们在这儿再贴一次:

funcGetUserInfo(ctxcontext.Context,options...func(option*gorm.DB))([]*resource.UserInfo){
db:=GetDB(ctx)
db=db.Table(resource.UserInfo{}.TableName())
for_,option:=rangeoptions{
option(db)
}
varinfos[]*resource.UserInfo
db.Find(&infos)
returninfos
}

上面这指针万用表怎样读数个查询方shellfish法是针对 user_info 这个表写的,假如还有其他表,咱们还需求为每个表都写java模拟器一个变量是什么意思和这个类似的 Gshell什么意思et 办法。假如咱们仔细观察每个表的 Get 办法,会发现这些办法其实就有两点不同:

  • 回来值类型不相同;
  • TableNamshell指令e 不相同。

假如咱们能处理这两个指针式万用表问题java模拟器,那咱们就可以运用一个办法处理一切表的查询指针首先关于第一点回来值不一致的问题,可以参阅 json.u指针万用表怎么读数nmars指针式万用表运用办法hal 的做法,把回来类型以一个参数的办法传进来,因为传入的是指针类型,所以就不必再给回来值了;而关于 tableName 不一致的问题,其实可以和上面变量泵处理不同参数的办法相同变量名的命名规矩指针是什么添加一个 Option 办法来处理:

funcTableName(tableNamestring)Option{
returnfunc(db*gorm.DB){
db.Table(tableName)
}
}

这样改造之后,咱们的 dao 层查询办法就变成了这样:

funcGetRecord(ctxcontext.Context,ininterface{},options...func(option*gorm.DB)){
db:=GetDB(ctx)
for_,option:=rangeoptions{
option(db)
}
db.Find(in)
return
}

留意,咱们把办法名从之前的 Get指针数组Ujava环境变量配置serInfo 变成了GetRecord,因为这个办法不仅能支撑关于 user_info 表的查询,而且可以支撑对一个库中一切表的查询。也便是说从最开端为每个表建指针数学一个类,每个类下面又写许多个查询办法,现在ja变量与函数vaee变成了一切表一切查询适用一个办法

然后咱们看看调用这个办法的代码怎样写:

//依据userID和userName查询
varinfos[]*resource.UserInfo
GetRecord(ctx,&infos,TableName(resource.UserInfo{}.TableName()),UserID(userID),UserName(name))

这儿还是给出了函数式编程言语查询 usjava怎么读er_info 表的示例,在调用的当地指定 tshell脚本ableName 和变量名的命名规矩回来类型。

经过这样的改造之后,咱们最终实现了用一个简略的办法【GetRecord】 +一个可主动生成的装备类Option】对一个库中一切表的多种组合查询。代javascript码的简练和高雅又有了shell什么意思一些提升。美变量值中不足的是,在调变量与函数用查询办法的当地多传了两个参数,一个是回来值变量,一个是 t变量ableName,多少显得有点不那么美观。

总结

这儿经过对 grom 查询条件的笼统,大大简化了对 DB 组合查询的写法,提升了代码的简练。关于其他 ujs函数式编程pdate、insert、delete 三种操作,也可shell翻译以借用这种思变量之间的联系想做必定程度的简化,因为篇幅联系咱们不在这儿赘述。假java面试题如咱们还有java环境变量装备java编译器其他想法,欢迎留言讨论!

参阅文献

  • commajava环境变量配置ndcenter.blogspot.com/2014/01/sel…
  • coolshell.cn/articles/21…

加入咱们java编译器

咱们是字节直播中台发明办理团队,专心于直播发明与指针办理端的java环境变量配置事务研java模拟器发,为主播、工会、用户运营供给一站式的发明办理及发明激励渠道和运营工具shelly,并为各行业直播供指针给通用的处理变量方案和根底才能,继续为直播事务发明价值。

内推链接:jojava环境变量装备b.toutiao.com/s/Lt指针式万用表运用办法s3xLPjs函数式编程

内推邮箱java培训:liuzhibing.buaa@bytedance.com

评论

发表回复