Martin Fowler:任何一个傻瓜都能写出计算机能够了解的代码。唯有写出人类容易了解的代码,才是优良的程序员。
大家闭着眼睛想一下什么是好代码?兴许你的脑海中沉没着一堆词:洁净
、 整洁
、 命名标准
、 正文正当
、 高内聚低耦合
……
人人都想写好代码,因为看好代码就如同看一位五官端正的男子,情绪愉悦、舒畅,而看蹩脚的代码就如同看见腐烂的食物,闻起来也有一股坏滋味。
大多数人写的代码都不能称之为好代码,一方面因为本人技能限度,另一方面也可能基本就分不清好代码和坏代码,上面笔者联合日常编码实际与大家分享一下常见的 代码坏滋味
。
坏滋味:Long Method(过长函数)
过长函数
简而言之就是函数长度超标了,包含 横向
和纵向
。
为什么过长函数是一种坏滋味?
横向过长 会导致无奈一眼就能看出这行代码的作用,须要用鼠标缓缓往后边拖,置信用小屏幕的小伙伴常常会遇到这个问题,拖动的过程会重大影响读代码的效率。
纵向过长 其实就是呈现了大函数,一个函数的行太多,使得函数难以读懂,代码批改难度大。
那么如何解决过长函数问题呢?
对于横向过长的问题,个别会在 IDE 中提前配置好最大宽度,比方 80 字符或者 120 字符(具体依据公司外部标准设置),而后格式化代码即可解决。
比方咱们在写 Java8 stream
链式表达式的时候能够会很长:
List<String> nodes = list.stream().filter().filter().map.filter().collect(Collectors.toList()); // 可能会十分长
其实咱们能够在. 之前换行,这样看起来高深莫测。
List<String> nodes = list.stream()
.filter()
.filter()
.map
.filter()
.collect(Collectors.toList());
对于纵向过长的问题其实就是这个办法或者函数职责不够繁多,一个函数中沉积太多功能。
重构的伎俩很简略:Extract Method
,踊跃抽取函数或办法,暗藏细节放弃职责繁多。
坏滋味:Large Class(过大的类)
过大的类也经常被成为 上帝类
(God Class),上帝类个别是指保护了太多功能(违反繁多职责准则),连上帝也看不懂你的代码。
常识小百科
设计模式的六大准则有:
Single Responsibility Principle:繁多职责准则
Open Closed Principle:开闭准则
Liskov Substitution Principle:里氏替换准则
Law of Demeter:迪米特法令
Interface Segregation Principle:接口隔离准则
Dependence Inversion Principle:依赖倒置准则
六个准则的首字母联结起来就是 SOLID,两个 L 当成一个。
那如何判断一个类是不是上帝类呢?
个别一个类同时满足以下 3 个条件就是上帝类:
(1)CPFD (Capsules Providing Foreign Data) 从多个不相干类(模块)中援用数据。
(2)WOC (Weighted Operation Count) 类的所有函数的圈复杂度之和超过 65。
(3)TCC (Tight Capsule Cohesion) TCC < 1/3 类须要具备低内聚的个性(类中间接相干的办法与全副办法之比小于 1 /3),也就是较少的 private 办法。
为什么过大的类是一种坏滋味?
过大的类承当了过多的职责,往往有很多反复代码,并且这些反复代码你还不容易发现,这根本就是坏滋味的开始。
过大的类被子类继承会导致其余坏滋味,比方 遗留的馈赠
。
如何解决过大的类这种问题呢?
通过观察这个过大类的属性,看有没有一些属性有关联,如果有能够应用 Extract Class
将这些关联属性形象到一个新类中,并将与这些属性相干的操作都 Move
到新的类中。
通过观察这个过大类的办法,看有没有一些函数或办法存在兄弟关联,如果有能够应用 Extract Subclass
(提炼子类)的伎俩将这些办法提炼到子类中,子类能够继承父类。将类似的行为办法汇集在一个类中拆分到多个类中,能够进一步将发放调用解耦开。
以上办法周而复始,一个大类就能够拆分为多个小的且职责繁多的类。
坏滋味:Duplicated Code(反复代码)
Robert C.Martin:反复可能是软件中所有邪恶的本源。
反复代码个别是因为复制粘贴造成的。需要迭代过程中为了不影响已有性能,通常是将之前的代码 copy
一份改改,而后匆匆上线。
那为什么反复的代码是一种坏滋味呢?
最间接的弊病就是如果你想批改一段代码逻辑,可能会脱漏,甚至须要屡次批改能力确保全副批改完。
如何解决反复代码的问题?
上面联合代码实际分几个场景别离形容。
场景 1:同一个类中两个办法含有雷同的表达式
class A {public void method1() {
logic1
logic2
logic3
}
public void method2() {
logic1
logic2
logic4
}
}
重构伎俩:将两个办法独特的逻辑形象进去。重构后:
class A {public void method1() {baseMethod();
logic3
}
public void method2() {baseMethod();
logic4
}
public void baseMethod() {
logic1
logic2
}
}
场景 2:两个具备雷同父类的子类内含有雷同的表达式 类 A 中有一个 method1,有三段逻辑。
class A extend Base {public void method1() {
logic1
logic2
logic3
}
}
类 B 中有一个 method2,也有三段逻辑。
class B extend Base {public void method2() {
logic1
logic2
logic3
}
}
重构伎俩:将反复代码形象成一个办法放在父类中,差别局部由子类各自实现。
重构后:
class Base {public void baseMethod() {
logic1
logic2
}
}
class A extend Base {public void method1() {baseMethod();
logic3
}
}
class B extend Base {public void method2() {baseMethod();
logic3
}
}
场景 3:两个毫无相干的类呈现反复代码
如果两个没有间接关联的类呈现反复代码,能够思考将反复的代码形象到一个独立的一般类或者工具类中,实用方能够应用组合的形式调用。
代码样例这里不再赘述,与场景 1 和 2 大同小异,置信聪慧的你肯定能明确。
坏滋味:Long Parameter List(过长参数列)
全局变量是个邪恶的货色,数据是共享的并且每个线程都能够批改,太多了容易导致程序不可控,所以大家喜爱将变量以行参的形式传递,长此以往参数列越来越长了。
为什么过长参数列是一种坏滋味?
办法参数的数量太多会导致代码可读性十分差,如果有多个重载办法它们的办法参数都十分多,在写代码时很难判断该调用哪一个。
当一个办法须要新增性能,每次都可能会新增一个办法参数,这样导致调用方每次都要从新适配,小心被打哦,耗子尾汁。
如何解决过长参数列这种坏滋味?
能够将多个参数封装到一个 DTO 对象
中,办法间的对象通过对象的传输而不是过长的参数。
数据传输对象(DTO)(Data Transfer Object),是一种设计模式之间传输数据的软件应用零碎。
特地须要揭示的是有些状况下长参数也是正当的,因为应用参数能够防止某些依赖关系的产生。在编码实际中咱们能够通过观察长参数的办法,如果这个办法常常变动那你就要思考重构这个办法了。根本准则:事不过三,过三重构
。
坏滋味:Shotgun Surgery(散弹式批改)
为什么散弹式批改是一种代码坏滋味?
如果须要批改某个小性能,你须要在泛滥不同的类中做批改,首先很难找全,其次很可能会脱漏,这种问题个别称之为散弹式批改。
public class A {@Value("${db.mysql.url}")
private String mysqlDbUrl;
}
public class B {@Value("${db.mysql.url}")
private String mysqlDbUrl;
}
如果有多个类都应用了 db.mysql.url
这个变量,如果前面要将 mysql
切到 Oracle
,那么可能会波及到多处批改。如何解决散弹式批改这种代码坏滋味呢?
能够应用 Move Method
(搬移函数)和 Move Field
(搬移字段)把所有须要批改的代码放进同 1 个类,如果临时没有适合的类,就创立一个。
坏滋味:Speculative Generality(沉默寡言将来性)
在工作中常常会听到有开发小伙伴说:昨天加班我将订单模块做了批改,将来能够……
听到这里你能够会鼓掌:牛叉啊,提前对性能模板预留了扩展性。然而不要急于故障,你看技术总监的脸黑着呢,为什么呢?这位小伙伴的代码可能是一种坏滋味:沉默寡言将来性
。
为什么沉默寡言将来性是一种代码坏滋味?
互联网需要迭代更新速度快,”将来能够“意味着当下并不需要,有时候适度的形象和预留扩大也会让零碎难以了解,并且可能 提前背上包袱 往前走。
代码上总是谈将来可能性,会让团队陷入泥沼。每次有业务变动,开发人员都会思考各种将来可能性,预留足够多的扩大接口,这无疑极大减少了代码复杂度,让一个可能疾速上线的需要变得慢下来。
如何解决沉默寡言将来性这种代码坏滋味呢?
在代码架构设计中有一个准则叫:Simple Design
(简略设计准则)。
当实现当下业务代码时须要思考四个准则:通过测试、揭示用意、打消反复、起码元素。
当须要为将来而写的代码时,能够干这些:
(1)删除那些觉的将来有用的参数、代码、办法调用。
(2)修改办法名,使办法名揭示当下业务场景的用意,防止形象的技术形容词。
如果代码的改变的确是将来必然会发现的,那么还是倡议保留。沉默寡言将来性更多是指开发人员无根据臆测将来,导致代码模块被适度设计。
坏滋味:Comments(过多的正文)
在《Clean Code》中列举了一些常见正文坏滋味:
自言自语
多余的正文
误导性正文
循规方正文
日志式正文
废话正文
用正文来解释变量意思
用来标记地位的正文
类的归属的正文
正文掉的代码
为什么过多的正文是一种代码坏滋味呢?
好的正文能够辅助开发人员疾速浏览了解代码,过多的正文或坏正文可能会升高代码的可读性。
在开发实际中常常有同学批改了代码然而正文没有同步批改,代码的实现曾经与正文内容不统一,容易产生误导。
如何解决过多的正文这种坏滋味呢?
(1)如果代码块不再应用请间接删除不要应用正文。
(2)办法、变量的命名尽量见名知意,防止用正文再解释一遍。
(3)如果较短的正文不能笼罩办法的含意,可能是这个办法职责不繁多,能够思考重构这个办法。
总结:
文章列举了几种比拟常见的代码坏滋味,心愿大家在工作编码中多多练习,争取人人都能写出到代码,让天下没有难读的代码。如果须要深刻学习代码坏滋味,举荐研读两本书:《重构: 改善既有代码的设计》
,《Clean Code》
。
— END —
日常厚脸皮求赞:你好技术人,先赞后看,养成习惯,你的赞是我后退路线上的能源。