《代码整洁之道》学习总结

1. 整洁代码

1.1 整洁的代码力求集中,每个函数,每个类和每个模块都全神贯注于一事,完全不受四周细节的干扰和污染。

1.2 减少重复代码,提高表达力,提早构建简单对象(即不要重复代码,只做一件事,表达力,小规模抽象)。

1.3 设计原则的引用,包括单一职责原则(Single Responsibility Principle,SRP),开放闭合原则(Open Closed Principle,OCP)和依赖倒置原则(Dependency Inversion Principle,DIP)

2. 有意义的命名

2.1 如果名称需要注释来补充,那就不算是名副其实。

2.2 在命名时可以选择指明了计量对象和计量单位的名称。

2.3 别用accountList来指明一组账号,除非它真的是List类型,List一词对程序员有特殊意义,容易引起错误的判断,用accountGroup或bunchOfAccount,甚至用accounts都会好一些。

2.4 长名称胜于短名称,搜得到的名称胜于用自造编码代写就的名称,当然短名称若能表达出明显的意图则更好。

2.5 如果接口和实现必须选一个来编码的话,选择实现。ShapeFactoryImpl,甚至是丑陋的CShapeFactory,都比对接口名称编码来的好。

2.6 类名和对象名应该是名词或名词短语,不应当是动词。

2.7 方法名应当是动词或动词短语。

2.8 重载构造器时,使用描述了参数的静态工厂方法名,可以考虑将相应的构造器设置为private,强制使用这种命名手段。(即通过构造器私有化,通过静态方法提供实例对象。)

2.9 当涉及多个概念(类似一系列controller,manager,driver等)时,可以通过公共类特征+s进行统一。

2.10 避免将同一单词用于不同目的,同一术语用于不同概念,即双关语。比如多个类中均有add方法,则按不同的语义情景进行命名,也可以通过给名称加前后缀,以此添加语境加以区分。

3. 函数

3.1 函数应该做一件事。做好这件事,只做这一件事。函数的语句都要在同一抽象层级上。

3.2 别害怕长名称,长而具有描述性的名称,要比短而令人费解的名称好。长而具有描述性的名称,要比描述性的长注释好。

3.3 使用与模块名一脉相承的短语,名词和动词给函数命名。

3.4 如果函数要对输入参数进行转换操作,转换结果就该体现为返回值。

3.5 如果函数需要两个,三个或三个以上参数,就说明其中一些参数应该封装为类了。

3.6 普遍而言,应避免使用输出参数(需求减少)。

3.7 在进行boolean值判断时,应当把指令与询问分隔开来,相当于可以把判断逻辑封装在函数里,用类似xxxIsTrue/Existed代替。

3.8 最好把try和catch代码块的主体部分抽离出来,另外形成函数。

3.9 使用异常代替错误码,新异常就可以从异常类派生出来,无需重新编译或重新部署。

3.10 在不断尝试中消灭重复。打磨代码,分解函数,修改名称,消除重复,甚至缩短和重新安置方法,拆散类,保持测试通过。

4. 注释

4.1 注释总是一种失败,我们总无法找到不用注释就能表达自我的方法,所以总要有注释。尽管有时也需要注释,我们也该多花心思尽量减少注释量。

4.2 用代码去解释你大部分的意图,唯一真正好的注释是你想办法不去写的注释。

4.3 注释的作用是解释未能自行解释的代码,如果注释本身还需要解释,那就太遗憾了。

4.4 虽然Javadoc对于公共API非常有用,但对于不打算作公共用途的代码就令人厌恶了。

5. 格式

5.1 几乎所有的代码都是从上往下读,从左往右读。每行展现一个表达式或一个子句,每组代码行展示一条完整的思路,这些思路用空白行区分开来。(比如不同方法间,展现垂直方向上区隔的作用)。

5.2 被调用的函数应该放在执行调用函数的下面,这样就建立了一种自顶向下贯穿源代码模块的良好信息流。 

5.3 水平分割中,强联系的代码单词之间不用空格分开,弱联系的用空格字符加强分隔效果。(类似乘法因子之间没加空格,因为它们具有较高优先级。加减法运算项之间用空格隔开,因为加法和减法优先级较低)。

6. 对象和数据结构

6.1 对象把数据隐藏于抽象之后,曝露操作数据的函数。数据结构曝露其数据,没有提供有意义的函数。(两种定义本质上是对立的)。

6.2 过程式代码难以添加新数据结构,因为必须修改所有函数。面向对象代码难以添加新函数,因为必须修改所有类。

6.3 得墨忒耳律认为:模块不应了解它所操作对象的内部情形,方法不应调用由任何函数返回的对象的方法(类似于调用了返回值结果的方法,效果呈现连续调用,也称“火车失事”)。

6.4 最为精炼的数据结构,是一个只有公共变量,没有函数的类。这种数据结构有时被称为数据传送对象,或DTO(Data Transfer Objects)。DTO是非常有用的结构,尤其是在于数据库通信,或解析套接字传递的消息之类场景中。

6.5 对象曝露行为,隐藏数据,便于添加新对象类型而无需修改既有行为,同时也难以在既有对象中添加新行为;数据结构曝露数据,没有明显的行为,便于向既有数据结构添加新行为,同时也难以向既有函数添加新数据结构。

7. 错误处理

7.1 错误处理很重要,但如果它搞乱了代码逻辑,就是错误的做法。

7.2 使用异常而非返回码,往往使用定义异常+错误码+Msg。

7.3 用特定对象返回代替业务逻辑与错误处理结合,将异常行为封装到指定对象中。

7.4 如果你打算在方法中返回null值,不如抛出异常,或是返回特例对象。如果你在调用某个第三方API中可能返回null值的方法,可以考虑用新方法打包这个方法,在新方法中抛出异常或返回特例对象。(类似于一个中间转换)。

7.5 如果将错误处理隔离看待,独立于主要逻辑之外,就能写出强固而整洁的代码。

8. 边界

8.1 边界上的接口(Map)是隐藏的,它能随来自应用程序其他部分的极小的影响而变动。

9. 单元测试

9.1 TDD三定律:                                      

 定律一  在编写不能通过的单元测试前,不可编写生产代码 。

 定律二  只可编写刚好无法通过的单元测试,不能编译也算不通过。

 定律三  只可编写刚好足以通过当前失败测试的生产代码。

9.2 测试代码和生产代码一样重要,需要保证可读性。

9.3 双重标准,有些事你大概永远不会在生产环境中做,而在测试环境中做却完全没有问题。

9.4 单个测试中的断言数量应该最小化。

9.5 最佳规则也许是应该尽可能减少每个概念的断言数量,每个测试函数只测试一个概念。

10. 类

10.1 系统应该由许多短小的类而不是少量巨大的类组成。每个小类封装一个权责,只有一个修改的原因,并与少数其他类一起协同达成期望的系统行为。

10.2 开放-闭合原则(Open Closed Principle,OCP):类应当对扩展开放,对修改封闭。在理想系统中,我们通过扩展系统而非修改现有代码来添加新特性。

10.3 依赖倒置原则(Dependency Inversion Principle,DIP),本质而言,DIP认为类应当依赖于抽象而不是具体细节。

(未完待续~)

猜你喜欢

转载自blog.csdn.net/zhang_jiayuan/article/details/84328316