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

知识共享许可协议 版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons

原文地址: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

猜你喜欢

转载自blog.csdn.net/qq_34464926/article/details/92813018