美文网首页
函数(clean code 学习笔记)

函数(clean code 学习笔记)

作者: HelenYin | 来源:发表于2020-02-25 15:11 被阅读0次

短小

  • 代码块和缩进
    ifelsewhile,其中的代码块应该只有一行。该行大抵是一个函数调用语句。这样不但能保持函数的短小,而且,因为块内调用的函数拥有比较说明性的名称,从而增加了文档上的价值。
    所以函数的缩进层不应该多余一层或者两层。

bad


good


只做一件事情

  • 函数应该做一件事情,做好一件事情,只做一件事情。
    要判断函数是否不止做了一件事,就是看是否能拆除一个函数。
  • 每个函数一个抽象层级
    函数中混杂不同抽象层级,往往让人迷惑,读者可能我发判断某个表达式是基础概念还是细节,一旦细节与基础概念混杂,更多的细节就会在函数中纠结起来。
自顶向下读代码

我们想让代码拥有自顶向下的阅读顺序。我们想要让每个函数后面都跟着位于下一抽象层级的函数。

switch 语句

使用描述性的名称

好名称的价值怎么好评都不为过
别害怕长名称,长而具有描述性的名称,要比短而令人费解的名称好。
长而具有描述性的名称,要比描述性的长注释好。
命名方式保持一致。

函数参数

最理想的参数数量是零,其次是1,再其次是2,应尽量避免3。有足够特殊的理由才能用三个以上参数。

一元函数的普遍形式
  1. 操作该参数,将其转化为其他的什么东西在输出。例如: InputStream fileOpen('MyFile')String类型的文件名转换为InputStream类型的返回值。
  2. 事件(event),这种形式有输入参数而无输出参数。程序将函数看作是一个事件,使用该参数修改系统状态。
    尽量避免不遵循这两个形式一元函数。
标致参数

不要向函数参数传入布尔值,这样做等于大声宣布本函数不止做了一件事。
例如: render(Boolean isSuite),应该把该函数一分为二renderForSuiterenderForSingleTest

二元函数

有两个参数的函数比一元函数难懂。但是当两个参数正好是单个值的有序组成部分二元参数就正好,比如new Point(0,0)
应该尽量利用一些机制将二元函数转为一元函数。

参数对象

如果一个函数看来需要两个或三个参数,就说明其中一些参数可以封装成类

可变参数

String.format("%s worked $.2f hours", names, hours)
如果可变参数像上例这样,就和类型为list的单个参数没有区别。这样一来String.format实则是二元参数。

void dyad(String name, Integer ...args)
动词与关键字

对于一元函数和参数,应该形成一个非常良好的动词/名词对形式,例如 write(name)writeField(name)这个名称更好,告诉我们name是一个field

无副作用


这段代码的副作用在Session.initialize()。原本checkPassword是用来检查密码的,该名称并没有按时他会初始化这次会话,所以当某个误信函数名称的使用者,想要检查用户的有效性,就有抹除当前会话的风险。
这一副作用是时序性耦合,也就是说checkPassword只能在特定时刻调用。

“指令”与“询问”规则

函数要么做什么事,要么回答什么,但是两者不能混用

public boolean set(String attribute, String value)

调用:

if (set("username", "helen")){}

这样意义不明确,应该改为

if (attributeExit("username")) {
  setAttribute("username", "helen");
}

上面就是“指令”与“询问”规则。

使用异常替代错误返回码

当我们直接返回错误码时,可能因为需要马上处理错误码,导致更深层次的嵌套,当错误码返回时要求调用者马上处理错误



如果使用异常替代返回错误码,错误代码就能从主路径代码中分离出来


抽离try/catch 代码块

最好把try catch的主体部分的代码抽离出来。比如上面的事例可以改为

public void delete (Page page) {
  try {
    deletePageAndAllReference(page);
  }
  catch (Exception e) {
    logError(e); 
  }
}
private void deletePageAndAllReference(Page page) {
  delete(page);
  registry.deleteReference(page.name);
  configKeys.deleteKey(page.name.makeKey());
}
private void logError(Excetion e) {
  logger.log(e.getMessage());
}

这样delete函数只与错误处理有关,deletePageAndAllReference函数只与删除一个页面有关。

错误处理就是一件事

函数应该只做一件事,错误处理就是一件事,所以错误处理函数不应该做其他事,如果try在某个函数中存在,他就该在这个函数的第一个单词,而且catch,finally后也不应该有其他代码。

消除重复代码

相关文章

网友评论

      本文标题:函数(clean code 学习笔记)

      本文链接:https://www.haomeiwen.com/subject/oggggctx.html