摘要:“interface”。容易被理解、使用的接口,是开发良好面向对象软件的关键
概述
- 良好的接口,只向用户展现必须展现的东西。如果一个接口暴露了过多的细节,需要将不必要暴露的东西隐藏起来,从而改进接口的质量
- 所有数据都应该隐藏起来。
- 所有可以隐藏的函数都应该被隐藏起来。hide method、remove setting method
修改函数名称。最简单、最重要。名称是程序写作者、阅读者交流的关键工具
- 只要能理解一段程序的功能,就应该大胆使用rename method,将自己所知道的东西传达给他人
- 在适当时机,修改变量名称、类名称
函数参数:add parameter、remove parameter
- 对象技术,可以保持参数列的简短
- preserve whole object:来自同一个对象的多个值被当作参数传递
- introduce parameter object:对象不存在,创建一个参数对象
- replace parameter with method:函数参数来自该函数可获取的一个对象=》避免传递参数
- replace parameter with explicit method:参数被用来在条件表达式中做选择依据
- parameter method:为数个相似函数添加参数,将它们合并到一起
警告:
并发编程往往需要使用较长的参数列,可以保证传递给函数的参数都是不可修改的。
- 例如:内置对象、值对象一定是不可变的
- 可以使用不可变对象取代这样的长参数列。但必须对此类重构保持谨慎
separate query from modifier:明确地将“修改对象状态”的函数和“查询对象状态”的函数分开设计
replace constructor with factory method:不需要知道搞糟函数要创建的对象属于哪个类
encapsulate downcast:将向下转型封装隐藏起来,避免让用户做那种动作
replace error code with exception:以错误代码表示程序异常
replace exception with test:测试
rename method:修改函数名
- 问题:函数的名称未能揭示函数的用途
- 解决:修改函数名称
- 动机:
- 提倡的编程风格:将复杂的处理过程分解成小函数
- 做不好=》费尽周折,却弄不清楚这些小函数各自的用途
- 解决关键:给函数起个好名字。准确表达它的用途(将函数上的注释变成函数名称)
- 一个函数名称不能很好表达其用途,应该立即修改。
- 代码首先是为人写的,其次才是为计算机而写。而人需要良好命名的函数
- 起个好名称并不容易,需要经验。要想成为一个真正的编程高手,起名的水平至关重要,函数签名中的其他部分也同样重要
- 如果重新安排参数顺序,能够提高代码的清晰度,大胆去做。可运用add parameter、remove parameter
- 做法:
- 检查函数签名:是否被超类、子类实现过。
- 是:针对每份实现分别进行下列步骤
- 声明一个新函数,将其命名为新名称。将旧函数的代码复制到新函数中,进行适当调整
- 修改旧函数,让其调用新函数
- 找出旧函数的所有引用点,改而调用新函数
- 删除旧函数
- 如果旧函数是该类public接口的一部分,可能无法安全地删除它。这种情况下,将其保留在原处,并标记为deprecated(不建议使用)
- 注意:添加、去除某个参数,过程大致相同
add parameter:添加参数
- 问题:某个函数需要从调用端得到更多信息
- 解决:为此函数添加一个对象参数,让该对象带进函数所需信息
- 动机:
- 必须修改一个函数,修改后的函数需要一些过去没有的信息=》需要给该函数添加一个参数
- 不使用本重构的时机:除了添加参数外,还有其他的选择
- 只要可能,其他选择都比添加参数要好:不会增加参数列的长度
- 过长的参数列是bad smell:程序员很难记住这么多参数=》data clumps
- 提问:
- 能从已有参数中得到需要的信息?
- 能通过某个函数提供所需信息?
- 需要将这些信息用于何处?此函数是否应该属于用改该信息的哪个对象所有
- 针对现有参数,加入新参数是否合适?是否可以使用intruduce parameter object
- 并非绝对不要添加参数。但是,在添加参数之前必须要了解其他选项
- 做法:类似add parameter、remove parameter
- 检查函数签名是否被超类、子类实现过?是:针对每份分别实现下列步骤
- 声明一个新函数。名称与原函数同,只是添加新参数;将旧函数的代码复制到新函数中
- 如果需要添加的参数不止一个,将其一次性添加进去比较容易
- 修改旧函数,令其调用新函数
- 可以给参数提供任意值。一般会给对象参数提供null;给内置型参数提供一个明显非正常值;数值型参数,建议使用0以外的值,这样比较容易将其认出来
- 找出旧函数的所有引用点,将其修改为对新函数的引用,删除旧函数
- 如果旧函数是该类public接口的一部分,可能无法安全地删除它。这种情况下,将其保留在原处,并标记为deprecated(不建议使用)
remove parameter:移除参数
- 问题:函数本体不再需要某个参数
- 解决:将该参数去除
- 动机:
- 可能经常添加参数,却往往不愿意去掉它们:无论如何,多余的参数不会引起任何问题,而且以后可能用得上
- 恶魔的诱惑
- 参数代表着函数所需的信息,不同的参数值有不同的意义。
- 函数调用者必须为每一个参数操心该传什么东西进去。如果不去掉多余参数,就是让每一位用户多费一份心。很不划算,且“去除参数”是非常简单的一项重构
- 多态函数,情况有所不同,不能去除原有函数:可能多态函数的另一份(或多份)实现会使用这个参数,此时就不能去除它。