将查询函数和修改函数分离Separate Query from Modifier
image.png- 动机:如果某个函数只是提供一个值,没有任何看得到的副作用,那么这是一个很有价值的东西。我可以任意调用这个函数,也可以把调用动作搬到调用函数的其他地方。这种函数的测试也更容易。简而言之,需要操心的事情少多了。
- 一个函数只承担一种职责。
函数参数化 Parameterize Function
image.png- 动机:如果我发现两个函数逻辑非常相似,只有一些字面量值不同,可以将其合并成一个函数,以参数的形式传入不同的值,从而消除重复。
移除标记参数Remove Flag Argument
image.png- 动机:“标记参数”是这样的一种参数:调用者用它来指示被调用函数应该执行哪一部分逻辑。参数name只是导流。如果调用者传入的是程序中流动的数据,这样的参数不算标记参数;只有调用者直接传入字面量值,这才是标记参数。另外,在函数内部实现上,如果参数值只是作为数据传递给其他函数,这就不是标记参数;只有参数值影响了函数内部的控制流,这才是标记参数。
保持对象完整Preserve Whole Object
image.png- 动机:如果我看见代码从一个记录结构中导出几个值,然后又把这几个值一起传递给一个函数,我会更愿意把整个记录传给这个函数,在函数体内部导出所需的值。“传递整个记录”的方式能够更好地应对变化:如果将来被调的函数需要从记录中导出更多的数据,我就不用为此修改参数列表。
以查询取代参数Replace Parameter with Query
image.png- 动机:函数的参数列表应该总结改函数的可变性,标示出函数可能体现出行为差异的主要方式。和任何代码中的语句一样,参数列表应尽量避免重复,并且参数列表越短越容易理解。
- 如果调用函数时传入了一个值,而这个值由函数自己来获得也是同样容易,这就是重复。这个本不必要的参数会增加调用者的难度,因为它不得不找出正确的参数值,其实原本调用者是不需要费这个力气的。
- 去除参数也就意味着“获得正确的参数值”的责任被转移:有参数传入时,调用者需要负责获得正确的参数值;参数去除后,责任就被转移给了函数本身。一般而言,我习惯于简化调用方,因此更愿意将责任交给函数本身,但如果函数难以承担这份责任,就另当别论了。
- 不使用“以查询取代参数”最常见的原因是,移除参数可能会给函数题增加不必要的依赖关系——迫使函数访问某个程序元素,而我原本不想让这个函数了解这个元素的存在。
以参数取代查询 Replace Query with Paramenter
image.png- 动机:在浏览函数实现时,我有时会发现一些令人不快的引用关系,例如,引用一个全局变量,或者引用另一个我想要移除的元素。为了解决这些令人不快的引用,我需要将其替换为函数参数,从而将处理引用关系的责任转交给函数的调用者。
移除设值函数Remove Setting Method
image.png- 动机:如果为某个字段提供了设值函数,这就暗示这个字段可以被改变。如果不希望在某个对象创建之后此字段还有机会被改变,那就不要为它提供设值函数(同时将改字段声明为不可变)。这样以来,该字段就只能在构造函数中赋值。
以工厂函数取代构造函数Replace Constructor with Factory Function
image.png- 构造函数的一些局限性:
- Java的构造函数只能返回当前所调用类的实例,也就是说,我无法根据环境或参数信息返回子类实例或代理对象
- 构造函数的名字时固定的,因此无法使用比默认名字更清晰的函数名。
- 构造函数需要通过特殊的操作符来调用,所以在要求普通函数的场合难以使用。
- 工厂函数不受这些限制,工厂函数的实现内部可以调用构造函数,但也可以换成别的方式实现。
以命令取代函数 Replace Function with Command
image.png- 动机:函数,不管是独立函数,还是以方法形式附着在对象上的函数,是程序设计的基本构造块。不过,将函数封装成自己的对象,有时也是一种有用的办法。这样的对象我称之为“命令对象”,这种对象大多只服务于单一函数,获得对该函数的请求,执行该函数,就是这种对象存在的意义。
- 优势:
- 提供了更大的控制灵活性和更强的表达能力。
- 支持附加的操作,例如撤销操作。
- 可以设值命令的参数值,从而支持更丰富的生命周期管理能力。
- 可以借助继承和钩子对函数行为加以定制。
- 只有当特别需要命令对象提供的某种能力而普通函数无法提供这种能力时,才考虑使用命令对象。
以函数取代命令 Replace Command with Function
image.png- 动机:命令对象为处理复杂计算提供了强大的机制。借助命令对象,可以轻松地将原本复杂的函数拆解为多个方法,彼此之间通过字段共享状态;拆解后的方法可以分别调用;开始调用之前的数据状态也可以逐步构建。但这种强大时有代价的。大多数时候,我 只是想调用一个函数,让它完成自己的工作就好。如果这个函数不是太复杂,那么命令对象可能显得费而不惠,我就应该考虑将其变回普通函数了。
Return Modified Value
image.png- 在提炼函数过程中,如果涉及到了给局部变量赋值,那么将计算过程提取出来,并将变化的值返回。
Replace Error Code with Exception
image.png- 动机
Replace Exception with Precheck
image.png- 动机
网友评论