设计模式之美
王争
前Google工程师,《数据结构与算法之美》专栏作者
立即订阅
20015 人已学习
课程目录
已更新 46 讲 / 共 100 讲
0/6登录后,你可以任选6讲全文学习。
开篇词 (1讲)
开篇词 | 一对一的设计与编码集训,让你告别没有成长的烂代码!
免费
设计模式学习导读 (3讲)
01 | 为什么说每个程序员都要尽早地学习并掌握设计模式相关知识?
02 | 从哪些维度评判代码质量的好坏?如何具备写出高质量代码的能力?
03 | 面向对象、设计原则、设计模式、编程规范、重构,这五者有何关系?
设计原则与思想:面向对象 (11讲)
04 | 理论一:当谈论面向对象的时候,我们到底在谈论什么?
05 | 理论二:封装、抽象、继承、多态分别可以解决哪些编程问题?
06 | 理论三:面向对象相比面向过程有哪些优势?面向过程真的过时了吗?
07 | 理论四:哪些代码设计看似是面向对象,实际是面向过程的?
08 | 理论五:接口vs抽象类的区别?如何用普通的类模拟抽象类和接口?
09 | 理论六:为什么基于接口而非实现编程?有必要为每个类都定义接口吗?
10 | 理论七:为何说要多用组合少用继承?如何决定该用组合还是继承?
11 | 实战一(上):业务开发常用的基于贫血模型的MVC架构违背OOP吗?
12 | 实战一(下):如何利用基于充血模型的DDD开发一个虚拟钱包系统?
13 | 实战二(上):如何对接口鉴权这样一个功能开发做面向对象分析?
14 | 实战二(下):如何利用面向对象设计和编程开发接口鉴权功能?
设计原则与思想:设计原则 (12讲)
15 | 理论一:对于单一职责原则,如何判定某个类的职责是否够“单一”?
16 | 理论二:如何做到“对扩展开放、修改关闭”?扩展和修改各指什么?
17 | 理论三:里式替换(LSP)跟多态有何区别?哪些代码违背了LSP?
18 | 理论四:接口隔离原则有哪三种应用?原则中的“接口”该如何理解?
19 | 理论五:控制反转、依赖反转、依赖注入,这三者有何区别和联系?
20 | 理论六:我为何说KISS、YAGNI原则看似简单,却经常被用错?
21 | 理论七:重复的代码就一定违背DRY吗?如何提高代码的复用性?
22 | 理论八:如何用迪米特法则(LOD)实现“高内聚、松耦合”?
23 | 实战一(上):针对业务系统的开发,如何做需求分析和设计?
24 | 实战一(下):如何实现一个遵从设计原则的积分兑换系统?
25 | 实战二(上):针对非业务的通用框架开发,如何做需求分析和设计?
26 | 实战二(下):如何实现一个支持各种统计规则的性能计数器?
设计原则与思想:规范与重构 (11讲)
27 | 理论一:什么情况下要重构?到底重构什么?又该如何重构?
28 | 理论二:为了保证重构不出错,有哪些非常能落地的技术手段?
29 | 理论三:什么是代码的可测试性?如何写出可测试性好的代码?
30 | 理论四:如何通过封装、抽象、模块化、中间层等解耦代码?
31 | 理论五:让你最快速地改善代码质量的20条编程规范(上)
32 | 理论五:让你最快速地改善代码质量的20条编程规范(中)
33 | 理论五:让你最快速地改善代码质量的20条编程规范(下)
34 | 实战一(上):通过一段ID生成器代码,学习如何发现代码质量问题
35 | 实战一(下):手把手带你将ID生成器代码从“能用”重构为“好用”
36 | 实战二(上):程序出错该返回啥?NULL、异常、错误码、空对象?
37 | 实战二(下):重构ID生成器项目中各函数的异常处理代码
设计原则与思想:总结课 (3讲)
38 | 总结回顾面向对象、设计原则、编程规范、重构技巧等知识点
39 | 运用学过的设计原则和思想完善之前讲的性能计数器项目(上)
40 | 运用学过的设计原则和思想完善之前讲的性能计数器项目(下)
设计模式与范式:创建型 (2讲)
41 | 单例模式(上):为什么说支持懒加载的双重检测不比饿汉式更优?
42 | 单例模式(中):我为什么不推荐使用单例模式?又有何替代方案?
不定期加餐 (3讲)
加餐一 | 用一篇文章带你了解专栏中用到的所有Java语法
加餐二 | 设计模式、重构、编程规范等相关书籍推荐
春节特别加餐 | 王争:如何学习《设计模式之美》专栏?
免费
设计模式之美
登录|注册

33 | 理论五:让你最快速地改善代码质量的20条编程规范(下)

王争 2020-01-17
上两节课,我们讲了命名和注释、代码风格,今天我们来讲一些比较实用的编程技巧,帮你切实地提高代码可读性。这部分技巧比较琐碎,也很难罗列全面,我仅仅总结了一些我认为比较关键的,更多的技巧需要你在实践中自己慢慢总结、积累。
话不多说,让我们正式开始今天的学习吧!

1. 把代码分割成更小的单元块

大部分人阅读代码的习惯都是,先看整体再看细节。所以,我们要有模块化和抽象思维,善于将大块的复杂逻辑提炼成类或者函数,屏蔽掉细节,让阅读代码的人不至于迷失在细节中,这样能极大地提高代码的可读性。不过,只有代码逻辑比较复杂的时候,我们其实才建议提炼类或者函数。毕竟如果提炼出的函数只包含两三行代码,在阅读代码的时候,还得跳过去看一下,这样反倒增加了阅读成本。
这里我举一个例子来进一步解释一下。代码具体如下所示。重构前,在 invest() 函数中,最开始的那段关于时间处理的代码,是不是很难看懂?重构之后,我们将这部分逻辑抽象成一个函数,并且命名为 isLastDayOfMonth,从名字就能清晰地了解它的功能,判断今天是不是当月的最后一天。这里,我们就是通过将复杂的逻辑代码提炼成函数,大大提高了代码的可读性。
// 重构前的代码
public void invest(long userId, long financialProductId) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.DATE, (calendar.get(Calendar.DATE) + 1));
if (calendar.get(Calendar.DAY_OF_MONTH) == 1) {
return;
}
//...
}
// 重构后的代码:提炼函数之后逻辑更加清晰
public void invest(long userId, long financialProductId) {
if (isLastDayOfMonth(new Date())) {
return;
}
//...
}
public boolean isLastDayOfMonth(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.DATE, (calendar.get(Calendar.DATE) + 1));
if (calendar.get(Calendar.DAY_OF_MONTH) == 1) {
return true;
}
return false;
}
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《设计模式之美》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(42)

  • 黄林晴
    打卡
    明天最后一天上班
    就放假了
    2020-01-17
    18
    20
  • 再见孙悟空
    不要在函数中使用布尔类型的标识参数来控制内部逻辑,true 的时候走这块逻辑,false 的时候走另一块逻辑。这明显违背了单一职责原则和接口隔离原则。我建议将其拆成两个函数,可读性上也要更好。这个深有感触
    2020-01-17
    2
    11
  • 青青子衿
    个人以为还有善用和合理运用各个编程语言提供的语法糖和语言特性。比如Java开发,工作中有的老程序员不喜欢不适应lambda表达式,实际上合理恰当的使用lambda表达式可以让代码简洁明了
    2020-01-17
    1
    6
  • 🐾
    老师晚上好、关于代码规范这块,是不是有好的Java开发脚手架推荐呢?我发现公司的代码没有统一的脚手架,各小组重复造轮子,想规范化这块,但又不知道有哪些通用的脚手架。

    作者回复: 可以看下这篇文章:
    https://mp.weixin.qq.com/s/0eOm3dBOlFUy8Si1_k7OAw

    代码中的很多低级质量问题不需要人工去审查,java开发有很多现成的工具可以使用,比如:checkstyle,findbugs, pmd, jacaco, sonar等。

    Checkstyle,findbugs,pmd是静态代码分析工具,通过分析源代码或者字节码,找出代码的缺陷,比如参数不匹配,有歧义的嵌套语句,错误的递归,非法计算,可能出现的空指针引用等等。三者都可以集成到gradle等构建工具中。

    Jacoco是一种单元测试覆盖率统计工具,也可以集成到gradle等构建工具中,可以生成漂亮的测试覆盖率统计报表,同时Eclipse提供了插件可以EclEmma可以直观的在IDE中查看单元测试的覆盖情况。

    Sonar Sonar 是一个用于代码质量管理的平台。可以在一个统一的平台上显示管理静态分析,单元测试覆盖率等质量报告。

    2020-01-17
    3
    5
  • linlong
    一般大公司都有自己的编程规范,但执行的效果取决于commiter,而最终还是项目交付进度决定的。
    2020-01-17
    1
    5
  • 守拙
    课堂讨论:

    简单说一个本人常用的改善项目可读性的方法:
    在每一个module/package下编写一个description.md,简要说明是做什么的,有哪些需要注意的地方.

    不会花很多时间,但可以提高项目整体的可维护性.
    2020-01-17
    3
  • 程斌
    作为一名phper,这里有很多话想说,但是最后汇成一句话,没有什么参数不是一个数组不能解决的。解决函数嵌套那块,挺实用的。
    2020-01-17
    7
    3
  • 失火的夏天
    for里面有时候会出现下标0的特殊判断,这个时候就把0下标单独拉出去玩,for从下标1开始。

    我发现我的代码风格居然和争哥有点像,我仿佛在膨胀😁
    2020-01-17
    2
  • batman
    老师公司制定的统一编码规范长什么样子,能不能供大家学习学习
    2020-01-30
    1
  • 桂城老托尼
    感谢争哥分享
    文中提交的技巧都是实际工作中code的原则,可以作为CR时代码规范项的参考标准。
    以前经常踩 问题3 的,主要理论依据就是对外隐藏更多的细节,但违反了单一职责。
    还有更多的代码规约方面的, Google Java代码规约 和 Alibaba Java 代码开发规范 其实都可以作为案头必备手册了,安利一下。
    2020-01-18
    1
  • Jxin
    1.先提问题:
    第一块代码里面,存在一点瑕疵:if (calendar.get(Calendar.DAY_OF_MONTH) == 1) { return true; } return false;
    直接 return calendar.get(Calendar.DAY_OF_MONTH) == 1 ; 即可。
    2.请老师谈谈你的看法
    A.boolean isSummer = date.after(SUMMER_START)&&date.before(SUMMER_END);if (isSummer){};
    这个场景是定义“isSummer”这个临时变量,还是if(date.after(SUMMER_START)&&date.before(SUMMER_END)){};好点。
    看过<重构>第三版,里面其实偏向于用函数代替临时变量(变量是魔鬼)。但这可能就会有这种if里面包含比较长的函数调用的场景,可读性其实不好,有点做了两件事的味道。但在代码重构上是比较好的,毕竟没有变量滥用带来的不确定性。拿捏不准,我最后是跟着<重构>的思路走。但这里特请栏主谈谈自己的看法。

    B.boolean isSummer = date.after(SUMMER_START)&&date.before(SUMMER_END); 是否需要写成final boolean isSummer。我的习惯对不可变临时变量都会加final,事实上我基本没有可变临时变量,对可变临时变量很敏感。final会导致语句行变长,但能规范代码,具有明确语义,方便其他人阅读和扩展(约束了行为)。这个也拿捏不准,栏主怎么看?

    C.类中成员属性按字母大小顺序排列。这个感觉不是很合理。拿订单类为例,我会让金额相关字段,地址相关字段,和状态相关字段分隔开各自聚合在一块。这时候就没办法按字母大小排,但语义更强。当然,对金额和地址字段,其实属于值对象,可以单独成类(存对象序列化)。但老项目难有这种设计,往往是一张表平级包含一切。所以这个按大小排序的规范,感觉太“任性”了。

    3.其他编程规范,篇幅有限,而且是死的东西,不罗列了。感兴趣的同学有时间看看<Effective java>(一礼拜),没时间就看看<阿里开发手册>(2小时)。平时工作重视Sonar的每个告警,慢慢积累就好了。
    2020-01-18
    1
  • 李小四
    设计模式_33
    使用参数作为控制逻辑,这一点深有感触,除了故意设计成这样,还有一些是改成这样的(不想改程序结构,或者不能改),在原来的基础上扩展功能,这样加一个用于控制逻辑的参数,程序就分成了两部分;如果后面再加,代码分成2^n个部分,而是会有大量的重复代码,同一个逻辑要该好几个地方,很容易忘。

    对于代码质量,我有些个人的心得就是:写完代码之后,再看看,如果发现“不舒服”的地方,多想一想。
    2020-01-17
    1
  • 刘大明
    1.命名长度问题
    2.利用上下文简化命名
    3.命名要可读,可搜索
    4.如何命名接口和抽象类
    5.注释应该怎么写
    6.注释是不是越多越好
    7.类和函数多大才合适
    8.一行代码多长才合适
    9.善于用空行分隔符
    10.缩进是两格还是四格
    11.大括号是否需要另起一行
    12.类中成员的排列顺序
    13.代码应该分割成更小的单元块
    14.函数参数不要过多
    15.不要用函数参数来控制逻辑
    16.函数设计要职责单一
    17.移除过深的嵌套
    18.学会使用解释性变量
    19.
    20.统一编码规范
    这些都是开发过程中,让代码更好的一些编码规范
    我自己在项目开发过程中也会时刻注意是否符合规范。
    自己在项目中还遇到很多人提交代码不写注释,
    因为重构很多注释掉的代码不删除
    重复代码不提取公共类
    临时代码随意修改,随意提交线上等等很多代码混乱问题。
    从自身做起,让代码更加整洁,提交的代码尽量减少代码的坏味道。
    2020-01-17
    2
    1
  • Chen
    函数中不要使用参数来做代码执行逻辑的控制。我之前写代码从来没关注到这点,学习了
    2020-01-17
    1
    1
  • DullBird
    对于不要把控制逻辑参数暴露出来,而是拆分成多个方案。这个点。我有点疑惑。
    1. 比方说有个组织查询组织下人的抽象,暴露了listUserByNode()的接口
    2. 组织包括(部门-员工),(班级-学生),由于某种原因,有4张表,部门表,员工,班级,学生。
    3. 如果我只想查询学生的时候 调用 listUserByNode(),传入type=student,但是由于底层表是分离的,实际上执行了另一段代码。只不过调用方认为这只是个筛选条件。

    还有是最近在看Dubbo,dubbo里面用的 spi机制,我感觉也是把控制留给了参数,实现对外代码通用。只不过它是用多态实现,我们有时候方法逻辑简单。就用if...else解决了。这点不是特别能理解。
    2020-02-08
  • javaadu
    打卡30:今日学习《设计模式之美》第33节,主要收获是:复习了改善代码可读性的编程技巧
    1. 避免多层嵌套、避免复杂的逻辑控制关系,移除过深的嵌套层次,方法包括:去掉多余的 if 或 else 语句,使用 continue、break、return 关键字提前退出嵌套,调整执行顺序来减少嵌套,将部分嵌套逻辑抽象成函数。
    2. 函数的职责要单一,避免用boolean变量做参数控制函数内部的逻辑
    3. 尽量抽取出不相关的子问题
    4. 配合《编写可读代码的艺术》和《代码整洁之道》一起阅读更好
    2020-01-24
  • wenxueliu
    英雄所见略同。除了每行缩进不一样之外,其他全部一致。能跟这样的人一起工作是最幸福的事。
    2020-01-22
  • 落叶飞逝的恋
    关于Java代码规范这块建议参考《阿里巴巴Java开发手册》,每个点都比较细
    2020-01-21
  • 牛顿的烈焰激光剑
    关于代码可读性,除非公司导入了提供统一的布局配置文件,否则绝对不要用 IDE 的全选代码再自动格式化。我以前有个 leader 就是这么干的,后来他就转行了。
    2020-01-21
  • Dimple
    最后一节课里的很多小细节我都是对号入座了,这也就间接说明我来了,是一件正确的事情。

    来这里,把很多对号入座的错误都找出来,并一一改进,那我还有什么遗憾的呢
    2020-01-19
收起评论
42
返回
顶部