《代码整洁之道》——(2)函数
目录
1.1、短小
函数的第一规则是要短小。
代码块和缩进
if语句、else语句、while语句等,其中的代码块应该只有一行。该行大抵应该是一个函数调用语句。这样不但能保持函数短小,而且,因为块内调用的函数拥有较具说明性的名称,从而增加了文档上的价值。
这也意味着函数不应该大到足以容纳嵌套结构。所以,函数的缩进层级不该多于一层或两层。
1.2、只做一件事
函数应该做一件事。做好这件事。只做一件事。
如果函数只是做了该函数名下同意抽象层上的步骤,则函数还是只做了一件事。编写函数毕竟是为了把大一些的概念(换言之,函数的名称)拆分为另一个抽象层上的一系列步骤。
1.3、每个函数一个抽象层级
自顶向下读代码:向下规则
我们想要让代码拥有自顶向下的阅读顺序。我们想要让每个函数后面跟着位于下一抽象层级的函数,这样一来,在查看函数列表时,就能循抽象层级向下阅读了。
1.4、switch语句
将switch语句埋到抽象工厂底下。
1.5、使用描述性的名称
别害怕长名称。长而具有描述性的名称,要比短而令人费解的名称好。长而具有描述性的名称,要比描述性的长注释好。
1.6、参数函数
1.6.1、一元函数的普遍形式
1.6.2、二元函数
有两个参数的函数要比一元函数难懂。
1.6.3、三元函数
有三个参数的函数要比二元函数难懂的多。排序、琢磨、忽略的问题都会加倍体现。建议你在写三元函数前一定要想清楚。
1.6.4、参数对象
如果函数看来需要两个、三个或三个以上参数,就说明其中一些参数应该封装为类了。
1.6.5、动词与关键字
给函数起个好名字,能较好的解释函数的意图,以及参数的顺序和意图。对于一元函数,函数和参数应当形成一种非常良好的动词/名词对形式。
1.6.6、无副作用
1.6.7、输出参数
普遍而言,应避免使用输入参数。如果函数必须要修改某种状态,就修改所属对象的状态吧。
1.7、分割指令与询问
函数要么做什么事,要么回答什么事,但二者不可得兼。函数应该修改某对象的状态,或是返回该对象的有关信息。两样都干常会导致混乱。
1.8、使用异常替代返回错误码
从指令式函数返回错误码轻微违反了指令与询问分割的规则。它鼓励了在if语句判断中把指令当作表达式使用。
if (deletePage(page) == E_OK)
这不会引起动词/形容词混淆,但却导致更深层次的嵌套结构。当返回错误码时,就是在要求调用者立刻处理错误。
另一方面,如果使用异常替代返回错误码,错误处理代码就能从主路径中分离出来,得到简化。
1.8.1、抽离Try/Catch代码块
Try/catch代码块丑陋不堪。它们搞乱了代码结构,把错误处理与正常流程混为一谈。最好把try和catch代码块的主体部分分离出来,另外形成函数。
1.8.2、错误处理就是一件事
函数应该只做一件事,错误处理就是一件事。因此,处理错误的函数不该做其他事。
1.8.3、Error.java依赖磁铁
返回错误码通常暗示某处有个类或是枚举,定义了所有的错误码。
这样的类就是一块依赖磁铁;其他许多类都得导入和使用它。当Error枚举修改时,所有这些其他的类都需要重新编译和部署。这对Error类造成了负面压力。程序员不愿增加新的错误代码,因为这样他们就得重新构建和部署所有东西。于是他们就复用旧的错误码,而不添加新的。
使用异常替代错误码,新异常就可以从异常类派生出来,无需重新编译或重新部署。
1.9、别重复自己
重复可能是软件中一切邪恶的根源。许多原则与实践规则都是为控制与消除重复而创建。
1.10、结构化编程
只要函数短小,偶尔出现的return、break或continue语句没有坏处,甚至比单入单出原则更具有表达力。
1.11、小结
每个系统都是使用某种领域特定语言搭建,而这种语言是程序员设计来描述系统的。
函数是语言的动词,类是名词。这并非是退回到那种认为需求文档中的名词和动词就是系统中类和函数的最初设想的可怕的旧观念。其实这是个历史更久的真理。编程艺术是且一直就是语言设计的艺术。
大师级程序员把系统当作故事来讲,而不是当程序来写。他们使用选定编程语言提供的工具构建一种更为丰富且更具表达力的语言,用来讲那个故事。那种领域特定语言的一个部分,就是描述在系统中发生的
各种行为的函数层级。在一种狡猾的递归操作中,这些行为使用它们定义的与领域紧密相关的语言讲述自己那个小故事。