第11章 重构API
将查询函数和修改函数分离
- 如果函数只是提供一个值,没有任何看得到的副作用,那么这是一个很有价值的东西。可以在任意地方调用该函数,需要操心的事情少多了。(命令和查询分离原则)
- 举例说明“看得到的副作用”,一种常用的优化方法是,将查询多得结果缓存于某个字段中,这样一来后续的重复查询就可以大大加快速度。虽然查询时改变了对象的缓存,因为不论如何查询,总是获得相同的结果,所以这一修改时察觉不到的。
函数参数化
- 如果两个函数逻辑非常相似,只有一些字面量值不同,可以将其合并成一个函数,以参数的形式传入不同的值,从而消除重复。
移除标记参数
- “标记参数”是这样的一种参数:调用者用它来指示被调用数应该执行哪一部分逻辑。如果调用者传入的是程序中流动的数据,这样的参数不算标记参数。
保持对象完整
- 如果代码从一个记录结构中导出几个值,然后又把这几个值一起传递给一个函数。我会更愿意把整个记录传给这个函数,在函数体内部导出所需的值。
- 优缺点:“传递整个记录”的方法能更好地要对变化、缩短参数列表,还便将通用处理逻辑搬移到完整对象中去。缺点是,被调函数依赖完整对象。当两者不在同一模块中,考虑不采用本手法。
以查询代替参数
- 函数参数列表应该尽量避免重复,列表越短越容易理解。如果调用函数时传入了一个值,这个值由函数自己来获得也是同样容易,这就是重复。
- 当移除参数,会给函数增加不必要的依赖关系,或者函数具有引用透明性(referential transpatency,即,不论任何时候,只要传入相同的参数值,改函数的行为永远一致),此时就要考虑使用本手法,是否得不偿失。
以参数取代查询
- 本手法和上一个手法互为逆向重构,目的多为保证函数的引用透明性。
移除设值函数
- 对于某些情况,我们不希望字段被改变,那么就应该去除设值函数。该字段只能在构造函数中被赋值。“不想让它被修改”的意图会更清晰。另一种情况是,新对象通过调用构造函数,然后通过一系列设值函数的调用,共同完成新对象的 构造。对于这种情况,也要想办法去除设值函数,更清晰地表达我的意图。
- 如果不能把“调用设值函数”替换为“创建一个新对象”,请放弃本重构。
以工厂函数取代构造函数
- 与一般的函数相比,够着函数常有一些丑陋的局限性。可以考虑以工程函数去掉构造函数。
以命令取代函数
- 将函数封装成自己的对象,又是也是一种有用的办法。这样的对象我称之为“命令对象”,或者简称“命令”(参考命令模式)。这种对象大多只服务于单一函数,获得对该函数的请求,执行该函数,这就是这种对象存在的意义。
- 命令对象,可以通过继承和钩子进一步定制函数行为,通过设置命令的参数值,可以支持更丰富的生命周期管理。 对于函数不是一等公民的编程语言,这个手法可以为函数提供大部分相当于一等公民的能力。*(在编程语言中,一等公民可以作为函数参数,可以作为函数返回值,也可以赋值给变量。)*命令对象可以轻松将原本复杂的函数拆解成多个方法,彼此之间通过字段共享状态。
以函数取代命令
- 当函数本身不是太复杂时,命令对象可能显得费而不惠。应该考虑将其变回普通函数。