[学习笔记]《代码整洁之道》(二)

[学习笔记] 《代码整洁之道》—第3章 函数

函数要短小,更短小

  • 20行封顶最佳;
  • 每一行都不应该太长;
  • if, else, while语句等,其中的代码块应该只有一行函数调用语句;
    • 调用的函数应该有一个较具说明性的名称。
  • 函数不应该大到足以容纳嵌套结构。
    • 缩进层级不应该多于一层或两层。

一个函数只做一件事,做好这件事

  • 函数只做该函数名下统一抽象层上的步骤。
  • 只做一件事的函数:
    • 不可能再从中再拆出一个新函数;
    • 无法被合理的切分为多个区段。

每个函数一个抽象层级

  • 自顶向下读代码:向下规则

    • 每个函数后面都跟着下一抽象层级的函数。

      void function_A(){
          function_B();
      }
      
      void function_B(){
          function_C();
          function_D();
      }
      
      void function_C(){
          function_c1();
      }
      
      void function_c1(){
          ...
      }
      
      void function_D(){
          ...
      }
      

switch语句

  • 很难写出短小的switch语句(if/else语句同样如是)。
    • 将switch语句都埋藏在较低的抽象层级;
    • 永不重复,只出现一次,用于创建多态对象。
  • 很难100%的执行。

使用描述性的函数名称

  • 函数越短小,功能越集中,就越便于取一个好名字;
  • 长而具有描述性的名字
    • 要比短而令人费解的名字好;
    • 要比描述性的长注释好
  • 选择描述性的名称有助于
    • 理清模块的设计思路;
    • 代码的改善重构。
  • 命名方式要保持一致
    • 使用与模块名一脉相承的短语、名词和动词给函数命名。

函数参数

  • 零参数函数最理想,其次是单参数函数,再次是双参数函数,应尽量避免三参数函数(除非有足够特殊的理由)。
    • 参数不易对付,概念性太多,阅读不易;
    • 从测试角度看,参数更叫人为难;
    • 输出参数比输入参数更难以理解。
      • 信息从参数输入函数,通过返回值从函数输出。而不是通过参数输出。

一元函数的普遍形式

  • 向函数传递单个参数有两种普遍的理由:1. 问关于该参数的问题, 2. 操作该参数。

    • 选用较能区别这两种理由的名称,而且总是一直的在上下文中使用这两种形式。
  • 还有一种不那么普遍但极有用的单参数函数形式:事件(event)。

    • 有输入参数,而无输出参数;
    • 将函数看作一个事件,使用该参数修改系统那个状态;
    • 谨慎地选用那个名称和上下文语境,让读者很清楚地了解它是个事件。

标识参数

  • 标识参数丑陋不堪;
  • 向函数传入布尔值简直是骇人听闻。

二元函数

  • 有两个参数的函数比一元函数难懂;
  • 当然有时两个参数正好;
  • 两个参数的前后顺序往往被搞错;
  • 尽量利用一些机制将二元函数转换成一元函数。

三元函数

  • 三个参数的函数更加难懂,写之前想清楚;

参数对象

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

    Circle makeCircle(double x, double y, double radius);
    Circle makeCircle(Point center, double radius);
    

参数列表

  • 有时,我们想要向函数传入数量可变的参数,例如:

    String.format("%s worked %.2f hours.", name, hours);

    如果像这样被等同对待,就和类型为List的单个参数没有区别。

动词与关键字

给函数取个好名字

  • 能较好地解释函数的意图

    • 对于一元函数,函数和参数应该形成一种良好的动词/名词对形式。

      write(name)就很好;

      更好的大概是writeField(name), 它告诉我们”name“是一个"field"。

  • 解释参数的顺序和意图

    • 把参数名称变成函数名

      assertEqual(expeacted, actual)改成assertExpectedEqualsActual(expeacted, actual)

      减轻了记忆参数顺序的负担。

无副作用

副作用是一种谎言!

  • 函数承诺只做一件事,但还是会做其他被藏起来的事。
    • 会导致古怪的时序性耦合及顺序依赖。
  • 应尽量避免使用输出参数
    • 如果函数必须要修改某种状态,就修改所属对象的状态吧!

分隔指令与询问

函数要么做什么事,要么回答什么事,但二者不可得兼。

  • 函数应该修改某对象的状态或是返回该对象的有关信息。
  • 两样都干常会导致混乱。

使用异常替代返回错误码

似懂非懂,没看明白, 郁闷,再接再厉!

别重复自己

代码的重复会导致问题

  • 代码臃肿;
  • 当算法改变时多处需要修改;
  • 也增加了多次放过错误的可能性。

重复可能是软件中一切邪恶的根源。

结构化编程

  • 只要函数够短小,偶尔出现returnbreakcontinue语句没有坏处,甚至比单入单出原则更具表达力。
  • goto只在大函数中才有道理,应该尽量避免使用。

如何写出这样的函数

  • 先写代码

    • 可能冗长而复杂,可能又过长的参数,名称也不合适,还会有重复;
    • 不过会配上一套单元测试,覆盖每行丑陋的代码。
  • 然后在打磨这些代码

    • 分解函数,修改名称,消除重复;
    • 缩短和重新安置方法;
    • 保持测试通过。
  • 遵循规则,组装好修改后的函数。

并不是从一开始就按照规则写函数

参考文献

[1] Robert C. Martin 著,韩磊 译,《代码整洁之道》,北京:人民邮电出版社,2010.1(2018.9 重印), ISBN 978-7-115-21687-8。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值