重构 API 旨在提升 API 的清晰度、简化其使用方式,并明确函数的功能边界,特别是区分查询和修改操作。
以下是这些技巧的整理和说明:
技巧(中文/英文) | 核心目标与动机 | 做法概览 | 示例/说明 |
将查询函数和修改函数分离 (Separate Query from Modifier) | 保持 API 清晰地分离 读取数据的函数(查询)和修改程序状态的函数(修改函数)。如果一个函数同时返回一个值并具有副作用(改变可观察状态),应将其拆分。 | 如果一个函数返回一个值 并且 具有副作用,则应拆分成两个函数:一个 查询函数(返回结果,没有副作用)和一个 修改函数(改变状态,通常返回 void)。 | 如果函数 alertForMiscreant(people) 既查找了不法分子,又触发了警报,应将其拆分为 findMiscreant(people) (查询) 和 alertForMiscreant(people) (修改函数,调用查询函数并触发警报)。 |
函数参数化 (Parameterize Function) | 消除多个函数之间 相似的重复代码,用一个通用函数取代功能相似、仅有字面量值差异的一组函数。 | 用 改变函数声明 为函数添加参数,以承载那些变化的字面量值。然后将所有相似的函数调用重定向到这个新的通用函数。 | 用一个 raise(aPerson, factor) 函数取代功能相似的 tenPercentRaise(aPerson) 和 fivePercentRaise(aPerson)。 |
移除标记参数 (Remove Flag Argument) | 消除用于指示被调函数执行哪一部分逻辑的 标记参数(flag argument),因为它们隐藏了差异性,使 API 难以理解。布尔型标记尤其糟糕。 | 将包含标记参数的函数替换为 多个明确的函数,每个函数完成标记参数所代表的一项独立任务。 | 用 setHeight(value) 和 setWidth(value) 取代根据传入字符串 name 决定设置哪个维度的 setDimension(name, value)。 |
保持对象完整 (Preserve Whole Object) | 避免从一个记录结构中取出多个值,并将它们作为独立参数传递给函数。将 整个记录或对象 完整地传给函数,可以缩短参数列表,并更好地应对未来函数对数据需求的变更。 | 修改函数声明,接受完整的对象作为参数。让函数体内部自行访问所需数据。 | 函数调用应从 aPlan.withinRange(low, high) 改为 aPlan.withinRange(aRoom.daysTempRange),传入完整的 daysTempRange 对象。 |
以查询取代参数 (Replace Parameter with Query) | 消除冗余参数,如果该参数的值可以通过查询函数(query)从 另一个已传入的参数或对象 中获得。 | 将函数体内引用该参数的地方改为调用新建的查询函数。全部替换完成后,使用 改变函数声明 将该参数去掉。 | 如果 discountedPrice(basePrice, discountLevel) 中的 discountLevel 可以通过调用 this.discountLevel 获得,则移除参数,让函数自己查询。 |
以参数取代查询 (Replace Query with Parameter) | 解决函数对 外部元素(如全局变量或需要移除的元素)的依赖关系,增强函数的 引用透明性。 | 将函数内部的查询操作提炼为参数,迫使函数的调用者提供该值。这通常涉及 提炼变量 和 提炼函数 的组合操作。 | 如果函数 targetTemperature 内部查询了 thermostat.currentTemperature 的值,则修改函数使其接受 currentTemperature 作为参数传入。 |
移除设值函数 (Remove Setting Method) | 确保对象字段在构造之后不被修改(即保持 不可变性),从而清晰表达设计意图并避免错误。 | 使用 改变函数声明 确保字段值通过构造函数传入。移除所有在构造函数之外对设值函数的调用,并使用 内联函数 消去设值函数。 | 如果 Person 类的 name 字段在对象创建后不应改变,则移除 setName 函数。 |
以工厂函数取代构造函数 (Replace Constructor with Factory Function) | 提高对象创建的 灵活性,避免构造函数的限制(如不能返回子类,命名受限)。 | 新建一个工厂函数,让它在内部调用现有的构造函数。修改所有调用构造函数的代码改为调用工厂函数。 | 用 createEmployee(name, typeCode) 函数取代直接调用 new Employee(name, typeCode),以便在工厂函数中处理类型选择和子类实例化逻辑。 |
以命令取代函数 (Replace Function with Command) | 当一个函数变得过于复杂,或需要支持 高级功能(如撤销、复杂生命周期管理、继承定制)时,将其封装成一个“命令对象”(command object)。 | 为目标函数创建一个类(命令对象)。使用 搬移函数 将函数移入新类,参数成为新类的字段。 | 一个复杂的 score(...) 函数可以被封装进 ScoreCommand 类,其逻辑位于 execute() 方法中。 |
以函数取代命令 (Replace Command with Function) | 如果命令对象过于简单,其带来的 复杂性 大于其提供的灵活性,则应将其变回普通的函数。 | 将“创建并执行命令对象”的代码提炼到一个函数中。将命令对象的逻辑(包括构造函数参数和支持函数)内联到这个新函数中,并删除命令类。 | 一个简单的 ChargeCalculator 类,如果其计算逻辑不复杂,应被替换为一个简单的函数 charge(customer, usage, provider)。 |
- Author:CoderWdd
- URL:https://www.wuinsights.top//article/cbe187c6-d257-4342-b4e7-0c2aa7b1527d
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts