消除代码中那一大坨参数列表的技巧你会了吗
1 方法为何要有参数?
因为不同方法之间需要共享信息。
但方法间共享信息的方式除了参数列表,还有全局变量。但全局变量总能带来意外之喜,所以,取消全局变量也是大趋势。于是参数列表就成了唯一选择,于是,只要你想到有什么信息要传给一个方法,就会直接将其加入参数列表,导致参数列表越来越长! 2 长参数列表怎么了?
参数列表一旦过长,你一个 crud boy就很难完全掌控这些逻辑了呀!所以症结是数量多,解决关键也就是降低参数数量。 3 解决方案3.1 聚沙成塔
一个简单的创建博客的方法: 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); }
如此,一旦后续需求又扩展了,需要增加创建博客所需的内容,则该参数列表是不变的,也就是说它是稳定的! 3.2 动静分离
若这个类不断膨胀,变成一个大类,该咋办?毕竟并非所有场景下,参数都属于同一个类: // 根据博客 ID 获取对应章节信息 public void getSections(final long acticleId, final HttpClient httpClient, final SectionProcessor processor) { HttpUriRequest request = createChapterRequest(acticleId); HttpResponse response = httpClient.execute(request); List sections = toSections(response); processor.process(sections); }
单论参数的个数,数量并不多。若你只看这个方法,很难发现直接问题。绝对数量不是core,参数列表也应该是越少越好。
但注意,每次传进来的参数: acticleId 都随请求不同而改变 但 httpClient、processor 两个参数一样,因为都有相同逻辑,没啥变化。
即acticleId 的变化频率同 httpClient 和 processor 这两个参数变化频率不同。
不同的数据变动方向也是不同关注点。 这里表现出来的就是典型的动数据(acticleId)和静数据(httpClient、processor),它们是不同关注点,应该分离。
针对该案例: 静态不变的数据完全可以成为这个方法所在类的一个字段 只要将每次变动的东西作为参数传递即可
因此,代码可重构如下: public void getSections(final long acticleId) { HttpUriRequest request = createChapterRequest(acticleId); HttpResponse response = this.httpClient.execute(request); List sections = toSections(response); this.processor.process(sections); }
这个怪味道是个软件设计问题,代码缺乏应有的结构,所以,原本应该属于静态结构的部分却以动态参数的方式传来传去,无形中导致参数列表变长。
长参数列表固然可以用一个类进行封装,但能够封装成这个类的前提是:这些参数属于同一个类,有相同的变化原因!
若方法的参数有不同的变化频率,就要看情况了。对静态部分,本小节案例已经看出,它可以成为软件结构的一部分,而若有多个变化频率,则还可以封装出多个参数类。 3.3 再见了,标记!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)。
只有短小的代码,我们才能有更好的把握,而要写出短小的代码,需要我们能够"分离关注点"。 总结
应对长参数列表主要的方式就是减少参数的数量,最直接的就是将参数列表封装成一个类。但并不是说所有的情况都能封装成类来解决,我们还要分析是否所有的参数都有相同的变动频率。
变化频率相同,则封装成一个类。
变化频率不同的话: 静态不变的,可以成为软件结构的一部分 多个变化频率的,可以封装成几个类
此外,参数列表中经常会出现标记参数,这是参数列表变长的另一个重要原因。对于这种标记参数,一种解决方案就是根据这些标记参数,将方法拆分成多个方法。
如果感觉小编写得不错,请素质三连:点赞+转发+关注。我会努力写出更好的作品分享给大家。更多JAVA进阶学习资料小编已打包好,可以关注私信找我领取哦!
自动洗碗机给餐饮行业带来了新的变化1。它节省了时间和精力。随着社会经济的发展,为了使我们的生活更加方便,机器的操作逐渐取代了劳动。现在连洗碗也不例外。商用洗碗机提高了餐具的清洗效率。除了高清洁度外,它们还大大减少了
2020年Q2东南亚手机市场份额出炉,OPPO排名亮了随着国产手机品牌的不断发展壮大,近两年不少国内手机厂商开始走出国门,纷纷往更广阔的海外市场发展扩张,得到了广大海外消费者的关注。近日,据韩联社的最新报道,在市调机构Counterp
华为成功突破,又一项新专利公布,手机行业或许将要ampampquot变天ampampquot众所周知,没有真正意义上的全屏手机。尽管弹出式摄像机可以全屏显示,但也有许多缺点。机械笨重,手机不防水,结构复杂且价格昂贵,所有制造商都放弃了这种设计,取而代之的是使用药丸屏幕,刘
餐厅用洗碗机的注意事项在日常使用中,大多数人会忽视商用洗碗机的维护,导致频繁出现故障,这是缺乏维护。即使是先进的智能商用洗碗机中,也不可避免地会不注意维护。这是商用洗碗机故障的正常现象,尽管故障不同。因
如何选择合适的自动洗碗机?随着生活条件的提高,餐饮行业越来越受欢迎,酒店工厂学校都开始使用商用洗碗机,那么如何选择合适的洗碗机?小编提出了以下几个观点。1。清洗速度要快,适用于餐厅餐厅餐具代替高运行速度。2
商用自动洗碗机的优势根据最近媒体关于洗碗机普及程度的报道,洗碗机在世界范围内的普及率为3040,在国外的普及率为7080。然而,对于如此高的数据,洗碗机在中国的受欢迎程度仍然相对较低。近年来,企业看中
超声波洗碗机和喷淋洗碗机的工作原理洗碗机按工作方式主要分为超声波洗碗机和喷淋洗碗机。超声波洗碗机我们都知道超声波洗碗机是使用超声波振动清洗的原理。超声波通过液体介质时,会压缩液体介质的高频振动,产生正负液体分子交替
连锁快餐店用洗碗机的优势商用洗碗机在某些方面有很好的效果,为用户提供了很多方便。商用洗碗机的优点是什么?商用洗碗机可以节约能源。一些大型商用洗碗机可设计为拐弯形式,对场地的要求相对宽松。此外,还可以节约人
学校使用食堂洗碗机的优势与人工洗碗机相比,使用学校洗碗机不仅有效地避免了餐具的卫生风险,保证了卫生安全,而且大大提高了洗碗效率和餐具的周转率。在人工清洗餐具的情况下,餐具每餐只能使用一次,因此需要配备35
饭店自动洗碗机的特点及注意事项中大型洗碗机适用于繁忙的大型食堂。与人工洗碗机和其他洗碗机不同,重复的工作可能会降低人工工作效率,而其他洗碗机可能无法清洁这么多餐具,从而降低清洗质量。大型洗碗机每小时可清洗960
纯电动车还得迈过的几道坎最近唱衰燃油车似乎越来越火了。其实纯电动车的发展恐怕还远不到成熟的时候,有其自身技术上的问题,也有基础设施的事,个人观察有这几道坎还得扛过去。一充电对于个人使用纯电车来说,充电续航