重构手法记录

上一篇:https://blog.csdn.net/a_higher/article/details/123046444https://blog.csdn.net/a_higher/article/details/123046444

常用手法。

1.提炼函数。y:花时间浏览代码才知道它在干什么。z:注意变量作用域

2.内联函数。y:内容和名字一样容易理解或太多中间层。z:使用函数内部实现代替函数,和提炼函数相反。

3.提炼变量。也叫引入解释性变量。y:变量比表达式更能理解。z:对一个复杂表达式使用局部变量分解。

4.内联变量。y:表达式比变量更能理解。z:去掉临时变量,使用临时变量值。

5.改变函数声明。y:名字不够清楚,或参数不行(参数相当于设置了一个上下文,只有在这个上下文中才能使用这个函数,如:电话号码格式转换,如果传入个人,就没有办法处理公司电话,如果改为传入电话,就能广泛使用,减少了模块依赖。但个人传入的话可以更好的访问个人的其他属性,提高了封装读,所以看情况选择)。z:函数改名,或参数改变。

ps:重构时,查看变更范围,如果不能一步到位修改函数声明和所有调用者,渐进迁移。1.先旧函数中调用新函数,再对每个调用者改为调用新函数。2.如果重构属于一个多态类,且每个实现都要这么做,a如果多态性在类继承体系中体现就在超类转发,b如果没有,就在每个实现类转发。3如果是对外发布的api,就把旧函数声明为“不推荐使用”,等过一段时间移除。

6.封装变量(变量作用域,可变不可变)。y:数据搬移难度大需要同时修改所有引用该数据的代码,比如全局变量,先封装成函数会容易一些。并且封装可以监控数据变化和使用情况。z:1.设置get和set,public和private2.更深封装,get返回副本或把数据变类(封装记录),这个客户端修改不会影响共享数据。

7.变量改名。y:名字不清晰。z:改名

===感觉之前都是基础,下面是上层建筑

8.引入参数对象。y:相同的数据项出没于一个又一个函数,形成数据泥团。而引入参数对象把这些数据组织起来可能可以帮助我们理解问题。z:参数变成类。

9.函数组合成类。y:一组函数总是在操作同一块数据,可以变成一个类。不仅减少参数传递,也能提供一个公共环境处理这些数据z:

ps:类,把数据和操作数据放到一起。

10.函数组合成变换。y:数据=》某些计算=》派生数据,这样的时候,把计算逻辑拿出。z:用副本去计算后返回

ps:与函数组合成类区别:代码中对原数据做更新,使用类。因为使用变化,派生数据存在副本中,原数据修改就会导致数据不一致。

到这里小总:把逻辑提炼成一个函数,把相关函数(逻辑)又组合起来

11.拆分阶段。y:一段代码处理两件不同的事情或可以分顺序分步骤执行。z:把第一阶段用到数据,第二阶段要用到的数据引入中转数据结构,通过传参传入第二阶段。

封装(对外界隐藏)

隐藏非临时变量

隐藏临时变量

隐藏类内部细节

具体方法

1.封装记录,也叫以数据类取代记录。y:对于可变数据,封装可以隐藏细节。map那些结构也要封装。z:将记录变类,设置get和set。

ps:嵌套封装。就是封装成的类A中有个类b成员变量或map之类的对象,A中要有b的get和set。同时可能为了不可变使用副本

2.封装集合。误区:对集合变量访问进行封装,get放回集合本身,则集合中数据被修改还不知道。y:可变数据z:对修改集合增加add、remove之类方法。如果必要get返回副本【不要直接使用集合字段返回集合的值】或返回只读代理【迭代器不会修改集合】。

ps:集合的引用也要封装,就是get,set啦

3.以对象取代基本类型。y:某些数据后面新增一些行为。

4.以查询取代临时变量。y:只被计算一次之后不再被修改的变量

5.提炼类。y:1.某些数据和函数总一起出现,某些数据变化彼此相依2.搬移一些字段和函数,其他字段和函数还有没有意义3.开发后期,发现子类化只影响类部分特性,或某些特性需要一种方式子类化,而某些特性需要另一种方式子类化。

6.内联类。y:1.与提炼类相反,这个类责任不用了2.重新安排2个类责任,先内联再提炼。

7.隐藏委托关系。y:也算是封装的一种。封装模块与模块之前关系。如果客户端通过服务对象得到另外一个对象,调用后者函数

8.移除中间人。y:与移除委托关系相反,过多委托是的服务类变成中间人

9.替换算法。y:新的算法比旧的简单太多

搬移

搬入搬出函数

函数内部移动

移除死代码

具体方法

1.搬移函数。y:1.一个函数频繁引用其他上下文中的元素,对自身上下文中元素却关心甚少。2.把函数搬移到一个更加通用的地方。3.观察函数上下文,看函数调用者是谁,自身调用什么函数,调用函数需要什么数据。可能还需要为函数创建一个上下文,可以用函数组合成类和提炼类。

2.搬移字段。为了一个适用于问题域的良好数据结构。y:1.一同出现,一同传参,需要规整到同一条记录中。2.修改一个字段需要在多个结构中做修改。

3.搬移语句到函数。1.调用函数前每个地方需要执行相同代码。=》提到函数中2.如果他们不像一个整体,就用一个新函数包上那些语句和那个函数。

4.搬移语句到调用者。1.随着系统演进,抽象边界可能会偏移,需要我们把在调用点前表现不同行为调整到函数开头或结尾。把差异代码搬移到调用点。

5.以函数调用取代内联代码。y:内联代码做的事情已有函数重复,但要注意改变了函数实现时,期不期望内联代码也改变

6.移动语句。y:相关代码聚集起来,比如,从A中取数据,写一串代码,又从A中取数据,就需要把代码聚集

7.拆分循环。y:1.循环中做了不止一件事,这样在修改时需要同时理解多件事。

8.以管道取代循环。

9.移除死代码。

重新组织数据

1.拆分变量(1.循环变量2.结果收集变量3…)。y:临时变量被赋值2次,说明承担了多个责任。

2.字段改名。

3.以查询取代派生变量。y:1.尽量限制可变数据的作用域。2.消除不必要的临时变量用函数计算。3.如果临时变量不可变,则可以不用如此重构。

4.将引用对象改为值对象。z:移除设置函数,即set。提供相等性判断函数。

ps:值对象和引用对象更新差异:值对象替换整个内部对象。引用对象保留原对象不动,更新内部对象属性。

注:共享对象为了其他对象看见共享对象修改应使用引用对象。不可变数据用值对象

5.将值对象改为引用对象。y:相当于共享。

简化条件逻辑

1.分解条件表达式。z:条件和条件分支提炼函数

2.合并条件表达式。y:检查条件不一致,行为一致

3.以卫语句取代嵌套条件表达式。y:两个条件的一些情况,z:先检查罕见条件,为真就return。如:

 ps:目的:if-then-else给人分支同样重要,无重点。卫语句则突出特殊情况。看起来像单一出口

4.以多态取代条件表达式。z:将条件逻辑拆分到不同场景,即条件变类,条件分支变类中函数。

5.引入特例。又叫引入空对象。y:需要检查某个特殊值,且处理也相同。

6.引入断言。y:只有某条件为真是,才运行代码

ps:目的:为了告诉阅读者,执行到这里的时候做了何种假设。

重构api

1.将查询函数和修改函数分离。y:命令与查询分离。有返回值的函数不应该有副作用,即既查又修改

2.函数参数化。y:逻辑相似的函数,看是否可以将差异作为参数传入

3.移除标记参数。y:根据参数传入判断走什么流程(如:if)z:根据参数每一种可能新建一个明确函数

4.保持对象完整。y:从一个记录结构中导出几个值,又把这几个值一起传递给一个函数=》把整个记录传给这个函数,函数内部去导入所需值。但这有点依恋情结

5.以查询取代参数。y:函数传入一个值可以由函数自己同样容易获得。意味着把调用者负责获得正确参数值的责任给了函数,会增加函数体依赖关系。所以要慎用。但如果去除参数只需要向另外一个参数查询得到或推导得出就完全可以用。

ps:如果某一函数只要传入相同参数,行为永远一致,又容易理解和测试,就不用

6.以参数取代查询。y:1.让目标函数不再依赖某个元素,则改为通过参数传入2.如果某一函数只要传入相同参数,行为永远一致,但内部有个元素使得失去这个特性。

7.移除设值函数。1.构造后不再更新该字段。2.创建脚本后不想再修改

8.以工厂函数取代构造函数。1.无法根据环境和参数信息返回子类实例或代理对象。2.构造函数需要通过特殊的操作符来调用。

9.以命令取代函数。y:将函数封装成自己的对象,该对象只服务于单一函数,获得对该函数请求,执行该函数,可以支持附加操作,如撤销。将"行为请求者"与"行为实现者"解耦。不是很懂。z:把所有局部变量变成字段。

ps:我有请求invoker,执行命令command,和助理receiver。当我收到一个买书请求,由这个请求new个command,告诉助理,又收到一个卖袜子请求,由这个请求new个command,再告诉助理。之后就告诉助理可以执行了,助理最终会到这个请求中执行请求逻辑。

10.以函数取代命令

处理继承关系(避免重复,有重复修改时要对重复一起修改)

1.函数上移。y:函数在各个子类中函数体相同。

ps:可能遇到的问题:1.函数有引用只出现在子类的字段等-》用字段上移和函数上移到超类。2.如果流程相似实现有差异,先塑造模板函数,构造好流程,实现交给子类或超类

2.字段上移。y:字段重复。如果是第一次赋值同时就完成声明而不是在类中定义字段,使用构造函数本体上移

3.构造函数本体上移。y:构造函数比普通函数多一些限制

4.函数下移。y:某个函数只与一个或少数几个子类有关(必须超类明确知道哪些子类需要这个函数,如果不知道用以多态取代条件表达式,留共用行为在超类。

5.字段下移。y:某个字段只被一个或一小部分子类用到

6.以子类取代类型码。问题:1.直接处理携带类型码这个类还是处理类型码本身。如:是“工程师”继承“员工”还是“员工”包含“员工类别类或员工类别属性”,然后“工程师”继承“员工类别类”

ps:类型码:表现:员工职位(工程师、经理、销售)。实现:枚举、符号、字符串、数字。取值:通常来自给系统提供服务的外部服务。

7.移除子类。与子类取代类型码相反。y:子类是针对差异编程,如果子类无用可以移除或变超类字段。

8.提炼超类。y:2个类做相似的事。做法:1继承和委托选择,继承就提炼类,委托就用组合

ps:真实世界结构可以作为设计继承提示,但很多时候是把一些共同元素抽取到一处,于是就有了继承

9.折叠继承体系。y:子类和超类没多大区别,把子类和超类合并

10.以委托取代子类。y:

ps:继承:只处理一个方向的变化。一个对象有明显类别之分用继承,子类的所有实例都应该是超类的实例。通过超类接口使用子类实例应该完全不出问题。

委托:可以处理不同变化。这是一个东西,这是另外一个东西,我只是使用其中一些功能。

案例:状态模式或策略模式

11。以委托取代超类。

下一篇:https://blog.csdn.net/a_higher/article/details/123137909https://blog.csdn.net/a_higher/article/details/123137909

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值