如何消除代码屎山中的一大坨参数列表?
有经验的程序员应该都见过,一个方法坐拥几十上百个参数。
方法为何要有参数?
因为不同方法间需共享信息。
但方法间共享信息的方式不止一种,除了参数列表,还有全局变量。但全局变量总能带来意外惊喜,所以,取消全局变量也是各大语言的趋势。
但方法之间还是要传递信息的,不能用全局变量,于是参数就成了唯一选择,于是,只要你想到有什么信息要传给一个方法,就会直接它加到参数列表中,参数列表也越来越长。
长参数列表的问题
参数列表过长,你一个 crud 程序员就很难完全掌控这些逻辑了呀!
所以症结是数量多,解决关键也就在于降低参数的数量。
解决方案
聚沙成塔
一个简单的创建博客的方法:
public void createActicle(final String title, final String introduction,final URL coverUrl,final ActicleType type,final ActicleColumn column,final String protagonists,final String tags,final boolean completed) {...Acticle acticle = Acticle.builder.title(title) .introduction(introduction).coverUrl(coverUrl).type(type).column(column).protagonists(protagonists).tags(tags).completed(completed).build();this.repository.save(acticle);
}
参数列表包含了一篇博客所要拥有的各种信息,比如:博客标题、博客简介、封面 URL、博客类型、博客归属的专栏、主角姓名、博客标签、博客是否完结…
如果只是想理解逻辑,或许你还会觉得参数列表挺合理,毕竟它把创建一篇博客所需的各种信息都传给了方法,这也是大部分人面对一段代码时理解问题的最初角度。
虽然这样写代码容易让人理解,但这不足以让你发现问题。
现在产品要求在博客里增加一项信息,标识这部博客是否是签约博客,也就是这部博客是否可收费,咋办?
很简单啊!我直接新增一个参数。很多屎山就这么来的,积少成多,量变引起质变!
这里所有参数都是创建博客所必需的。所以,可以做的就是将这些参数封装成一个类,一个创建博客的参数类:
public class NewActicleParamters {private String title;private String introduction;private URL coverUrl;private ActicleType type;private ActicleColumn column;private String protagonists;private String tags;private boolean completed;...
}
这样参数列表就只剩下一个参数了:
public void createActicle(final NewActicleParamters parameters) {...
}
所以, 将参数列表封装成对象吧 !
只是把一个参数列表封装成一个类,然后,用到这些参数的时候,还需要把它们一个个取出来,这会不会是多此一举呢?就像这样:
public void createActicle(final NewActicleParamters parameters) {...Acticle acticle = Acticle.builder.title(parameters.getTitle()) .introduction(parameters.getIntroduction()).coverUrl(parameters.getCoverUrl()).type(parameters.getType()).channel(parameters.getChannel()).protagonists(parameters.getProtagonists()).tags(parameters.getTags()).completed(parameters.isCompleted()).build();this.repository.save(acticle);
}
若你也这样想,说明:你还没有形成对软件设计的理解。我们并非简单地把参数封装成类,站在设计角度,这里引入的是一个新模型。
一个模型的封装应该以【行为】为基础。
之前没有这个模型,所以想不到它应该有什么行为,现在模型产生了,它就该有自己配套的行为。
那这个模型的行为是什么?构建一个博客对象,这很清晰,则代码就能进一步重构:
public class NewActicleParamters {private String title;private String introduction;private URL coverUrl;private ActicleType type;private ActicleColumn column;private String protagonists;private String tags;private boolean completed;public Acticle newActicle() {return Acticle.builder.title(title) .introduction(introduction).coverUrl(coverUrl).type(type).column(column).protagonists(protagonists).tags(tags).completed(completed).build();}
}
创建博客的方法就得到了极大简化:
public void createActicle(final NewActicleParamters parameters) {...Acticle acticle = parameters.newActicle();this.repository.save(acticle);
}
“如何扩展需求”?如果需求扩展,需要增加创建博客所需的内容,那这个参数列表就是不变的,相对来说,它就是稳定的。
那这个类就会不断膨胀,变成一个大类,那该怎么办呢?如何解决大类?
动静分离
不是所有情况下,参数都属于一个类:
public void getChapters(final long acticleId, final HttpClient httpClient,final ChapterProcessor processor) {HttpUriRequest request = createChapterRequest(acticleId);HttpResponse response = httpClient.execute(request);List<Chapter> chapters = toChapters(response);processor.process(chapters);
}
根据博客 ID 获取其对应章节信息。
纯以参数个数论,参数数量不多。
如果你只是看这个方法,可能很难发现直接问题。绝对数量不是关键点,参数列表也应该是越少越好。
在这几个参数里面,每次传进来的 acticleId 都不一样,随请求不同而改变。但 httpClient 和 processor 两个参数一样,因为都有相同逻辑,没什么变化。
即acticleId 的变化频率同 httpClient 和 processor 这两个参数变化频率不同。
不同的数据变动方向也是不同关注点。这里表现出来的就是典型的动数据(acticleId)和静数据(httpClient 和 processor),它们是不同关注点,应该分离。
具体到这个场景下,静态不变的数据完全可以成为这个方法所在类的一个字段,而只将每次变动的东西作为参数传递就可以了。按照这个思路,代码可以改成这个样子:
public void getChapters(final long acticleId) {HttpUriRequest request = createChapterRequest(acticleId);HttpResponse response = this.httpClient.execute(request);List<Chapter> chapters = toChapters(response);this.processor.process(chapters);
}
这个坏味道其实是一个软件设计问题,代码缺乏应有的结构,所以,原本应该属于静态结构的部分却以动态参数的方式传来传去,无形之中拉长了参数列表。
长参数列表固然可以用一个类进行封装,但能够封装出这个类的前提条件是:这些参数属于一个类,有相同变化原因。
如果方法的参数有不同的变化频率,就要视情况而定了。对于静态的部分,我们前面已经看到了,它可以成为软件结构的一篇分,而如果有多个变化频率,我们还可以封装出多个参数类。
告别标记
public void editChapter(final long chapterId, final String title, final String content, final boolean apporved) {...
}
待修改章节的ID、标题和内容,最后一个参数表示这次修改是否直接审核通过。
前面几个参数是修改一个章节的必要信息,重点在最后这个参数。
从业务上说,如果是作者进行编辑,之后要经过审核,而如果编辑来编辑的,那审核就直接通过,因为编辑本身扮演了审核人的角色。所以,你发现了,这个参数实际上是一个标记,标志着接下来的处理流程会有不同。
使用标记参数,是程序员初学编程时常用的一种手法。正是这种手法实在太好用,导致代码里flag肆意飘荡。不仅变量里有标记,参数里也有。很多长参数列表其中就包含了各种标记参数。
在实际的代码中,必须小心翼翼地判断各个标记当前的值,才能做好处理。
解决标记参数,一种简单的方式就是,将标记参数代表的不同路径拆分出来。
这里的一个方法可以拆分成两个方法,一个方法负责“普通的编辑”,另一个负责“可以直接审核通过的编辑”。
// 普通的编辑,需要审核
public void editChapter(final long chapterId, final String title, final String content) {...
}
// 直接审核通过的编辑
public void editChapterWithApproval(final long chapterId,final String title,final String content) {...
}
标记参数在代码中存在的形式很多,有的是布尔值、枚举值、字符串或整数。都可以通过拆分方法的方式将它们拆开。在重构中,这种手法叫做移除标记参数(Remove Flag Argument)。
只有短小的代码,我们才能有更好地把握,而要写出短小的代码,需要我们能够“分离关注点”。
总结
应对长参数列表主要的方式就是减少参数的数量,最直接的就是将参数列表封装成一个类。但并不是说所有的情况都能封装成类来解决,我们还要分析是否所有的参数都有相同的变动频率。
变化频率相同,则封装成一个类。
变化频率不同的话:
- 静态不变的,可以成为软件结构的一篇分
- 多个变化频率的,可以封装成几个类
此外,参数列表中经常会出现标记参数,这是参数列表变长的另一个重要原因。对于这种标记参数,一种解决方案就是根据这些标记参数,将方法拆分成多个方法。
减少参数列表,越少越好。
如何消除代码屎山中的一大坨参数列表?相关推荐
- 如何消除代码山中那一大坨参数列表
本文分享自华为云社区<如何消除代码屎山中的一大坨参数列表?>,作者: JavaEdge . 有经验的程序员应该都见过,一个方法坐拥几十上百个参数. 1 方法为何要有参数? 因为不同方法之间 ...
- 如何消除代码shi山中的一坨参数列表?
- R语言可视化绘制及PDF使用字体参数列表:查看字体列表、可视化绘制图像中的字体参数列表、字体示例并写入pdf
R语言可视化绘制及PDF使用字体参数列表:查看字体列表.可视化绘制图像中的字体参数列表.字体示例并写入pdf 目录 R语言可视化绘制及PDF使用字体参数列表:查看字体列表.可视化绘制图像中的字体参数列 ...
- 某程序员动了公司祖传代码屎山,半年没改完,惭愧后交辞职报告
前段时间,有这样的一个话题,非常的火热,那就是关于程序员的,新入职程序员吐槽老员工写的代码就像是"一坨屎"!这样的言论瞬间就引起了程序员们的讨论. 有程序员认为,别看现在像是一坨屎 ...
- 某程序员动了公司的祖传代码“屎山”,半年后怒交辞职报告!
Python实战社群 Java实战社群 长按识别下方二维码,按需求添加 扫码关注添加客服 进Python社群▲ 扫码关注添加客服 进Java社群▲ 来源:网络 前段时间,有这样的一个话题,非常的火热, ...
- C语言中函数的参数列表为空和void的区别
C标准和C++标准在main函数上是有区别的,所以我分别详细来介绍他们. 对于C语言: C89标准的main()函数是可接受的,尽管现在建议是使用C99的标准.C99标准只定义了如下两种可接受的函数原 ...
- c语言全局变量作为参数_在C / C ++中使用变量参数列表
c语言全局变量作为参数 C/C++ provides a means to pass a variable number of arguments to a function. This artic ...
- c语言理解参数,c语言中对可变参数列表的简单理解
函数原型中一般情况下参数的数目是固定的,但是如果想在不同的时候接收不定数目的参数时该怎么办呢?c语言提供了可变参数列表来实现. 可变参数列表是通过宏来实现的,这些宏定义在stdarg.h的头文件中.头 ...
- linux中 tar 报参数列表过长,四种解决”Argument list too long”参数列表过长的办法...
在linux中删除大量文件时,直接用rm会出现:-bash: /bin/rm: 参数列表过长,的错误. 这时可以用find命令来结合使用. 例: 1.rm * -rf 改为: find . -name ...
最新文章
- python两台电脑文件传输_python实现简单socket程序在两台电脑之间传输消息的方法...
- 将servlet数据传到html_Servlet详解(二)
- npm 安装yarn_问题解决记录-npm和yarn全局安装成功后命令无法执行的问题
- 一个DDOS病毒的分析(二)
- Android基础夯实--你了解Handler有多少?
- zabbix之web监控
- Mysql高级之主从复制
- “庆渝年”​又更新了!法院裁定:禁止李国庆接触、骚扰、殴打俞渝
- mybatis中$和#号的区别
- Web API-定时器
- 红米note5刷android,红米Note5 安卓9.0 解锁Bootloader-刷入第三方TWRP_Recovery 获取完整ROOT教程...
- HLS第十二课(bayer photo)
- iMeta: 整合宏组学重新认识生命和环境科学
- 北京月薪高于1.7万的开发者占比远超其它地区;和黄医药获霸菱亚洲1亿美元股权投资 | 美通企业日报...
- 【排序】堆排序详解 附代码
- 2022年全球市场总线插头总体规模、主要生产商、主要地区、产品和应用细分研究报告
- 做了7年开源数据库开发,我学到了什么?
- 做电商网站如何选购云服务器?
- Vue打包后图片路径问题
- linux+显卡超频软件,安装和使用GreenWithEnvy在Linux上超频Nvidia显卡
热门文章
- 如何将HTTP站点转换成HTTPS、及后续问题
- 怎么把m4v转换为mp4?分享几种简单的处理方式
- Saltstack_使用指南04_数据系统-Grains
- SpringMVC测试代码(MockMvc)
- 【latex algorithm2e】持续更新
- Java Mybatis Error selecting key or setting result to parameter object
- 某饮料厂在举办促销,某饮料可凭3个瓶盖再换一瓶,并且可以一直循环下去(不允许暂借和赊账)请你计算如果某人不浪费瓶盖,尽量的参加活动,那么对于他初始买入的n瓶饮料,最后他一共能喝到多少瓶。
- java静态代码块、静态方法、静态变量、构造代码块、普通代码块、成员变量执行顺序
- 华为P8 电信青春版手机实现ssh登陆的方法
- 点云地面点滤波-progressive TIN densification(PTD)算法介绍