欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

函数-《代码整洁之道》读书笔记(二)

程序员文章站 2022-04-26 23:28:30
...

原文地址:https://liujiao111.github.io/2019/06/19/clean-code-function/

目录:

函数是代码中必不可缺的程序单元,那怎样的函数才算是好的函数呢?

短小

函数代码行数应该尽量保持少,每个函数都只做一件事,让每个函数看上去都一目了然。
例如,初始代码:

public static String renderPageWithSetupsAndTeardowns(PageData pageData,
                                                          boolean isSuite) throws Exception {
        boolean isTestPage = pageData.hasAttribute("Test");
        if(isTestPage) {
            wikiPage testPage = pageData.getWikiPage();
            StringBuffer newPageContent = new StringBuffer();
            includeSetupPages(testPage, newPageContent, isSuite);
            newPageContent.append(pageData.getContent());
            includeTeardownPages(testPage, newPageContent, isSuite);
            pageData.setContent(newPageContent.toString());
        }
        
        return pageData.getHtml();
    }

重构后:

public static String renderPageWithSetupsAndTeardowns(PageData pageData,
                                                          boolean isSuite) throws Exception {
        boolean isTestPage = pageData.hasAttribute("Test");
        if(isTestPage) {
            includeSetupAndTeardownPages(PageData, isSuite);
        }
        return pageData.getHtml();
    }

代码块和缩进:
if、else、while语句等,其中的代码块应该只有一行,该行大抵是函数调用语句,这样不但能保保持函数短小,,也因为块内调用的函数拥有较具有说明性的名称,从而增加了文档的价值。
函数的缩进层级不应该多于一层或两层,易于阅读和理解。

只做一件事

一个函数应该只做一件事,做好这件事。只做一件事的函数无法被合理地切分为多个区段

每个函数一个抽象层级

要确保函数只做一件事,函数中的语句都要在同一抽象层级上。函数中混杂不同抽象层级往往让人迷惑。
尽量让代码拥有自顶向下的阅读顺序。本篇末尾的代码遵循了这一规则。

switch语句

写出短小的switch语句很难,因为它天生就要做好多事,也包括if/else语句,不过还是得确保每个条件语句都在较低的抽象层级,而且永不重复,这可以利用多态来实现。例如,初始代码:

public Money calculatePay(Employee e) {
        switch (e.type) {
            case COMMISSIONED:
                return calculateCommission(e);
            case HOUTLY:
                return calculateHourlyPay(e);
            case SALARIED:
                return calculateSalaroed(e);
             default:
                 return new InvalidEmplyeeType(e.type);
        }
    }

该函数的问题:

  • 太长,当出现新的雇员类型时,会更长;
  • 明显做了不止一件事;
  • 违背了单一权责原则;
  • 违背了开放闭合原则,因为每当添加新类型时,就必须修改
  • 到处都有类似的函数结构:例如isPayDay(Employee e, Date date),或者
    deliverPay(Employee e, Money pay);

解决办法:

  • 将switch语句埋到抽象工厂下,不让任何人看到
  • 工厂使用switch语句为Emplyee的派生物创建适当的实体
    代码如下:

Employee:

public abstract class Employee {
    
    public abstract boolean isPayday();
    
    public abstract Money calcalatePay();

    public abstract Money deliverPay(Money pay);
}

工厂接口EmplyeeFactory:

public interface EmplyeeFactory {

    public Employee makeEmployee(EmplyeeRecord r);
}

工厂实现类

public class EmplyeeFactoryImpl implements EmplyeeFactory {
    @Override
    public Employee makeEmployee(EmplyeeRecord r) {
        switch (r.type) {
            case COMMISSIONED:
                return CommissionEmployee(r);
            case HOUTLY:
                return HourlyEmployee(r);
            case SALARIED:
                return SalaroedEmploee(r);
            default:
                return new InvalidEmplyeeType(r.type);
        }
    }
}

使用描述性的名称

函数名称要能极好地描述函数做的事,例如将testTableHtml改为SetUPTeardownIncluder.render。函数越小,功能越集中,就越便于取个好名字

  • 别害怕长名称,长而具有描述性, 好的描述性名称能帮助你理清模块设计思路;
  • 别害怕花时间取名字;
  • 命名方式要统一

函数参数

函数参数越少越好,如果有三个参数及以上,就要考虑函数设计是否合理。

一元函数的普遍形式

函数应该是操作参数或者将其转换为什么东西再输出这些动作,因此名称应该能表达出对参数操作的信息,例如
boolean fileExist(“MyFile”)这样。

标识参数

向函数传入布尔值简直是骇人听闻的做法,千万别这么做,应该把判断后的逻辑写成不同的函数。

二元函数

参数越多,函数越难懂。当然,有些情况下不可避免。应该尽量将其转换为一元函数,例如将某个参数写成成员变量,或者在构造器中传入。

三元函数

三元函数比二元函数难懂的多,排序、琢磨、忽略的问题会加倍出现。要尽量避免

参数对象

如果一个函数需要两个、三个以及以上的参数,就需要考虑将参数封装为类了、

参数列表

可变参数放在最后一个参数位置,其他参数应该尽量保证不超过2个。

动词与关键字

对于一元函数,函数和参数应该形成一种非常良好的动词/名词对形式,例如write(name),就比较好,甚至writeFiled(name)也不错
assertEqual改为assertExpectedEqualsActual(expected, actual)更好。

无副作用

函数承诺只做一件事,但是还会做其他隐藏起来的事情,这应该是要避免的情况。或者在函数名称中说明,或者去除其他隐藏的操作、
避免输出参数

分隔指令与询问

使用异常替代返回错误码

使用异常替代返回错误码,错误处理代码就能从主路径中分离出来,得到简化

抽离try/catch代码块

try/catch代码块丑陋不堪,搞乱了代码结构,把错误处理与正常流程混为一谈,最好把它们抽离成另外的函数

错误处理就是只做一件事

减少重复代码块

结构化编程

总结

写程序应该像是在讲故事,而不是真的当程序来写。

电子书免费共享:链接:
https://pan.baidu.com/s/1wvoRJGonA70J9hFn_w5jwA
提取码: 37jy