重构改善既有代码的设计-学习(五):重构API

1、将查询函数和修改函数分离(Separate Query from Modifier)

 

        例如: 

function getTotalOutstandingAndSendBill() {
    // 查询
    const result = customer.invoices.reduce((total, each) => each.amount + total, 0);
    // 修改
    sendBill();
    return result;
}

        改为:

// 查询
function totalOutstanding() {
    return customer.invoices.reduce((total, each) => each.amount + total, 0);
}

// 修改
function sendBill() {
    emailGateway.send(formatBill(customer));
}

2、函数参数化(Parameterize Function) 

 

        如果两个函数逻辑非常相似,只有一些字面量值不同,可以将其合并成一个函数,以参数的形式传入不同的值,从而消除重复。 

3、移除标记参数(Remove Flag Argument)

 

         “标记参数”是这样的一种参数:调用者用它来指示被调函数应该执行哪一部分逻辑。

        标记参数让人难以理解到底有哪些函数可以调用、应该怎么调用。拿到一份API以后,我首先看到的是一系列可供调用的函数,但标记参数却隐藏了函数调用中存在的差异性。使用这样的函数,我还得弄清标记参数有哪些可用的值。 

        如果一个函数有多个标记参数,可能就不得不将其保留,否则我就得针对各个参数的各种取值的所有组合情况提供明确函数。不过这也是一个信号,说明这个函数可能做得太多,应该考虑是否能用更简单的函数来组合出完整的逻辑。

       重构例子:

function setDimension(name, value) {
    if (name === "height") {
        this._height = value;
        return;
    }
    if (name === "width") {
        this._width = value;
        return;
    }
}

        改为:

function setHeight(value) {this._height = value;}
function setWidth (value) {this._width = value;}

4、 保持对象完整(Preserve Whole Object)

 

        如果我看见代码从一个记录结构中导出几个值,然后又把这几个值一起传递给一个函数,我会更愿意把整个记录传给这个函数,在函数体内部导出所需的值。 

        例如: 

const low = aRoom.daysTempRange.low;
const high = aRoom.daysTempRange.high;
if (aPlan.withinRange(low, high))

        改为:

if (aPlan.withinRange(aRoom.daysTempRange))

5、以查询取代参数(Replace Parameter with Query) 

 

         函数的参数列表应该总结该函数的可变性,标示出函数可能体现出行为差异的主要方式。和任何代码中的语句一样,参数列表应该尽量避免重复,并且参数列表越短就越容易理解。

        例如:

availableVacation(anEmployee, anEmployee.grade);
function availableVacation(anEmployee, grade) {
// calculate vacation...

        改为:

availableVacation(anEmployee)
function availableVacation(anEmployee) {
    const grade = anEmployee.grade;
    // calculate vacation...

6、以参数取代查询(Replace Query with Parameter) 

 

        在浏览函数实现时,我有时会发现一些令人不快的引用关系,例如,引用一个全局变量,或者引用另一个我想要移除的元素。为了解决这些令人不快的引用,我需要将其替换为函数参数,从而将处理引用关系的责任转交给函数的调用者。

        需要使用本重构的情况大多源于我想要改变代码的依赖关系——为了让目标函数不再依赖于某个元素,我把这个元素的值以参数形式传递给该函数。 

7、移除设值函数(Remove Setting Method)

 

        如果不希望在对象创建之后此字段还有机会被改变,那就不要为它提供设值函数(同时将该字段声明为不可变)。

        这里个人认为有些偏激,不过作者的目的是要强调不可变性。

8、以工厂函数取代构造函数(Replace Constructor with Factory Function)

 

        构造函数常有一些丑陋的局限性。以Java的构造函数为例:

  • 只能返回当前所调用类的实例。也就是说,我无法根据环境或参数信息返回子类实例或代理对象;
  • 构造函数的名字是固定的,因此无法使用比默认名字更清晰的函数名;
  • 构造函数需要通过特殊的操作符来调用(在很多语言中是new关键字),所以在要求普通函数的场合就难以使用。 

        工厂函数就不受这些限制。工厂函数的实现内部可以调用构造函数,但也可以换成别的方式实现。

  • 19
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值